Changeset 1043
- Timestamp:
- 10/30/07 18:54:13 (15 months ago)
- Location:
- trunk
- Files:
-
- 3 added
- 11 modified
-
Audio/AudioPlayer.m (modified) (12 diffs)
-
Audio/AudioScheduler.m (modified) (2 diffs)
-
Audio/Decoders/AudioDecoder.h (modified) (4 diffs)
-
Audio/Decoders/AudioDecoder.m (modified) (3 diffs)
-
Audio/Decoders/AudioDecoderMethods.h (added)
-
Audio/Decoders/LoopableRegionDecoder.h (added)
-
Audio/Decoders/LoopableRegionDecoder.m (added)
-
Audio/ScheduledAudioRegion.h (modified) (3 diffs)
-
Audio/ScheduledAudioRegion.m (modified) (5 diffs)
-
Database/AudioStream.h (modified) (2 diffs)
-
Database/AudioStream.m (modified) (2 diffs)
-
Play.xcodeproj/project.pbxproj (modified) (6 diffs)
-
Utilities/PUIDUtilities.mm (modified) (2 diffs)
-
Utilities/ReplayGainUtilities.m (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Audio/AudioPlayer.m
r1039 r1043 24 24 #import "AudioLibrary.h" 25 25 #import "AudioStream.h" 26 #import "AudioDecoder.h"27 26 28 27 #include <CoreServices/CoreServices.h> … … 244 243 NSLog(@"AudioPlayer error: Unable to reset AUGraph AudioUnits: %i", err); 245 244 246 AudioDecoder *decoder = [AudioDecoder audioDecoderForURL:[stream valueForKey:StreamURLKey] error:error];245 id <AudioDecoderMethods> decoder = [stream decoder:error]; 247 246 if(nil == decoder) 248 247 return NO; … … 300 299 } 301 300 302 // Determine the subrange of the stream to play, if any303 NSNumber *streamStartingFrame = [stream valueForKey:StreamStartingFrameKey];304 NSNumber *streamFrameCount = [stream valueForKey:StreamFrameCountKey];305 ScheduledAudioRegion *region = nil;306 307 // For reasons related to SQLite (see http://sqlite.org/nulls.html), -1 is used instead of NULL308 if(-1 == [streamStartingFrame intValue] && -1 == [streamFrameCount intValue])309 region = [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder];310 else if(-1 == [streamFrameCount intValue])311 region = [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startingFrame:[streamStartingFrame longLongValue]];312 else313 region = [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startingFrame:[streamStartingFrame longLongValue] frameCount:[streamFrameCount unsignedIntValue]];314 315 301 // Schedule the region for playback, and start scheduling audio slices 316 [[self scheduler] scheduleAudioRegion: region];302 [[self scheduler] scheduleAudioRegion:[ScheduledAudioRegion scheduledAudioRegionWithDecoder:decoder]]; 317 303 [[self scheduler] startScheduling]; 318 304 … … 329 315 return NO; 330 316 331 AudioDecoder *decoder = [AudioDecoder audioDecoderForURL:[stream valueForKey:StreamURLKey] error:error];317 id <AudioDecoderMethods> decoder = [stream decoder:error]; 332 318 if(nil == decoder) 333 319 return NO; … … 345 331 if(NO == formatsMatch || NO == channelLayoutsMatch) 346 332 return NO; 347 348 // Determine the subrange of the stream to play, if any 349 NSNumber *streamStartingFrame = [stream valueForKey:StreamStartingFrameKey]; 350 NSNumber *streamFrameCount = [stream valueForKey:StreamFrameCountKey]; 351 ScheduledAudioRegion *region = nil; 352 353 // For reasons related to SQLite (see http://sqlite.org/nulls.html), -1 is used instead of NULL 354 if(-1 == [streamStartingFrame intValue] && -1 == [streamFrameCount intValue]) 355 region = [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder]; 356 else if(-1 == [streamFrameCount intValue]) 357 region = [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startingFrame:[streamStartingFrame longLongValue]]; 358 else 359 region = [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startingFrame:[streamStartingFrame longLongValue] frameCount:[streamFrameCount unsignedIntValue]]; 360 333 361 334 // The formats and channel layouts match, so schedule the region for playback 362 [[self scheduler] scheduleAudioRegion: region];335 [[self scheduler] scheduleAudioRegion:[ScheduledAudioRegion scheduledAudioRegionWithDecoder:decoder]]; 363 336 364 337 return YES; … … 393 366 - (BOOL) streamSupportsSeeking 394 367 { 395 return ([self hasValidStream] && [[[ self scheduler] regionBeingRendered] supportsSeeking]);368 return ([self hasValidStream] && [[[[self scheduler] regionBeingRendered] decoder] supportsSeeking]); 396 369 } 397 370 … … 449 422 if(kAudioTimeStampSampleTimeValid & timeStamp.mFlags) { 450 423 SInt64 lastRenderedFrame = [self startingFrame] + timeStamp.mSampleTime - _regionStartingFrame; 451 [self setStartingFrame:[[[ self scheduler] regionBeingScheduled] seekToFrame:lastRenderedFrame]];424 [self setStartingFrame:[[[[self scheduler] regionBeingScheduled] decoder] seekToFrame:lastRenderedFrame]]; 452 425 [self setPlayingFrame:0]; 453 426 } … … 476 449 477 450 if(nil != currentRegion && [[currentRegion decoder] supportsSeeking]) { 478 SInt64 totalFrames = [ currentRegiontotalFrames];479 SInt64 currentFrame = [ currentRegioncurrentFrame];451 SInt64 totalFrames = [[currentRegion decoder] totalFrames]; 452 SInt64 currentFrame = [[currentRegion decoder] currentFrame]; 480 453 SInt64 desiredFrame = currentFrame + (SInt64)(seconds * [[currentRegion decoder] format].mSampleRate); 481 454 … … 492 465 493 466 if(nil != currentRegion && [[currentRegion decoder] supportsSeeking]) { 494 SInt64 currentFrame = [ currentRegioncurrentFrame];467 SInt64 currentFrame = [[currentRegion decoder] currentFrame]; 495 468 SInt64 desiredFrame = currentFrame - (SInt64)(seconds * [[currentRegion decoder] format].mSampleRate); 496 469 … … 507 480 508 481 if(nil != currentRegion && [[currentRegion decoder] supportsSeeking]) { 509 SInt64 totalFrames = [ currentRegiontotalFrames];482 SInt64 totalFrames = [[currentRegion decoder] totalFrames]; 510 483 [self setCurrentFrame:totalFrames - 1]; 511 484 } … … 627 600 currentFrame = [self totalFrames ] - 1; 628 601 629 [self setStartingFrame:[[[ self scheduler] regionBeingScheduled] seekToFrame:currentFrame + _regionStartingFrame]];602 [self setStartingFrame:[[[[self scheduler] regionBeingScheduled] decoder] seekToFrame:currentFrame + _regionStartingFrame]]; 630 603 [self setPlayingFrame:0]; 631 604 … … 691 664 #endif 692 665 693 [self setTotalFrames:[ regiontotalFrames]];666 [self setTotalFrames:[[region decoder] totalFrames]]; 694 667 695 668 [self willChangeValueForKey:@"hasValidStream"]; -
trunk/Audio/AudioScheduler.m
r1017 r1043 21 21 #import "AudioScheduler.h" 22 22 #import "ScheduledAudioRegion.h" 23 #import "AudioDecoder.h"24 23 25 24 // ======================================== … … 94 93 95 94 // Determine if region rendering is complete 96 if([[scheduler regionBeingRendered] atEnd] && [[scheduler regionBeingRendered] framesRendered] == [[scheduler regionBeingRendered] framesScheduled]) { 95 if([[[scheduler regionBeingRendered] decoder] currentFrame] == [[[scheduler regionBeingRendered] decoder] totalFrames] 96 && [[scheduler regionBeingRendered] framesRendered] == [[scheduler regionBeingRendered] framesScheduled]) { 97 97 98 98 // Notify the delegate -
trunk/Audio/Decoders/AudioDecoder.h
r884 r1043 22 22 #include <CoreAudio/CoreAudioTypes.h> 23 23 24 #import "AudioDecoderMethods.h" 25 24 26 // ======================================== 25 27 // Error Codes … … 34 36 }; 35 37 36 // A decoder reads audio data in some format and provides it as 32-bit float non-interleaved PCM37 @interface AudioDecoder : NSObject 38 // Superclass for an audio decoder covering an entire file 39 @interface AudioDecoder : NSObject <AudioDecoderMethods> 38 40 { 39 41 NSURL *_url; // The location of the stream to be decoded … … 45 47 } 46 48 47 + (AudioDecoder *) audioDecoderForURL:(NSURL *)url error:(NSError **)error; 49 // Return an AudioDecoder of the appropriate class 50 + (AudioDecoder *) decoderWithURL:(NSURL *)url error:(NSError **)error; 48 51 49 52 // Designated initializer … … 52 55 // The stream this decoder will process 53 56 - (NSURL *) URL; 54 55 // The type of PCM data provided by this AudioDecoder56 - (AudioStreamBasicDescription) format;57 - (NSString *) formatDescription;58 59 // The layout of the channels this AudioDecoder provides60 - (AudioChannelLayout) channelLayout;61 - (NSString *) channelLayoutDescription;62 63 // Attempt to read frameCount frames of audio, returning the actual number of frames read64 - (UInt32) readAudio:(AudioBufferList *)bufferList frameCount:(UInt32)frameCount;65 66 // The native (PCM) format of the source file67 - (AudioStreamBasicDescription) sourceFormat;68 - (NSString *) sourceFormatDescription;69 70 // ========================================71 // Input audio information72 // ========================================73 - (SInt64) totalFrames;74 - (SInt64) currentFrame;75 - (SInt64) framesRemaining;76 77 - (BOOL) supportsSeeking;78 - (SInt64) seekToFrame:(SInt64)frame;79 80 57 @end -
trunk/Audio/Decoders/AudioDecoder.m
r884 r1043 47 47 } 48 48 49 + (AudioDecoder *) audioDecoderForURL:(NSURL *)url error:(NSError **)error49 + (AudioDecoder *) decoderWithURL:(NSURL *)url error:(NSError **)error 50 50 { 51 51 NSParameterAssert(nil != url); … … 166 166 167 167 if((self = [super init])) { 168 _url = [url retain];168 _url = [url copy]; 169 169 170 170 // Canonical Core Audio format … … 257 257 } 258 258 259 - (SInt64) totalFrames { return -1; }260 - (SInt64) currentFrame { return -1; }259 - (SInt64) totalFrames { return 0; } 260 - (SInt64) currentFrame { return 0; } 261 261 - (SInt64) framesRemaining { return ([self totalFrames] - [self currentFrame]); } 262 262 -
trunk/Audio/ScheduledAudioRegion.h
r1025 r1043 20 20 21 21 #import <Cocoa/Cocoa.h> 22 23 22 #include <AudioToolbox/AudioToolbox.h> 24 23 25 @class AudioDecoder; 24 #import "AudioDecoderMethods.h" 26 25 27 // This class is a bit of an amalgam- it contains all the logic for accessing a subrange of 28 // audio from a Decoder, but also the buffers and associated internal state that 29 // AudioScheduler needs to use an object of this class. 26 // A class encapsulating an AudioDecoder and the buffers and associated internal state that 27 // AudioScheduler needs to use a decoder 30 28 @interface ScheduledAudioRegion : NSObject 31 29 { 32 AudioDecoder *_decoder; 33 AudioTimeStamp _startTime; 34 SInt64 _startingFrame; 35 UInt32 _frameCount; 36 unsigned _loopCount; 30 id <AudioDecoderMethods> _decoder; 37 31 38 UInt32 _framesReadInCurrentLoop;39 SInt64 _totalFramesRead;40 unsigned _completedLoops;32 AudioTimeStamp _startTime; 33 34 ScheduledAudioSlice *_sliceBuffer; 41 35 42 BOOL _atEnd; 43 44 // ======================================== 45 // AudioScheduler members 46 ScheduledAudioSlice *_sliceBuffer; 36 unsigned _numberSlices; 37 unsigned _framesPerSlice; 47 38 48 unsigned _numberSlices; 49 unsigned _framesPerSlice; 50 51 SInt64 _framesScheduled; 52 SInt64 _framesRendered; 39 SInt64 _framesScheduled; 40 SInt64 _framesRendered; 53 41 } 54 42 55 // ======================================== 56 // Creation 57 // ======================================== 58 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder; 43 + (ScheduledAudioRegion *) scheduledAudioRegionWithDecoder:(id <AudioDecoderMethods>)decoder; 44 + (ScheduledAudioRegion *) scheduledAudioRegionWithDecoder:(id <AudioDecoderMethods>)decoder startTime:(AudioTimeStamp)startTime; 59 45 60 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startingFrame:(SInt64)startingFrame; 61 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount; 62 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount loopCount:(unsigned)loopCount; 46 - (id) initWithDecoder:(id <AudioDecoderMethods>)decoder; 47 - (id) initWithDecoder:(id <AudioDecoderMethods>)decoder startTime:(AudioTimeStamp)startTime; 63 48 64 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime; 65 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime startingFrame:(SInt64)startingFrame; 66 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount; 67 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount loopCount:(unsigned)loopCount; 68 69 // ======================================== 70 // Properties 71 // ======================================== 72 - (AudioDecoder *) decoder; 73 - (void) setDecoder:(AudioDecoder *)decoder; 49 - (id <AudioDecoderMethods>) decoder; 50 - (void) setDecoder:(id <AudioDecoderMethods>)decoder; 74 51 75 52 - (AudioTimeStamp) startTime; 76 53 - (void) setStartTime:(AudioTimeStamp)startTime; 77 54 78 - (SInt64) startingFrame;79 - (void) setStartingFrame:(SInt64)startingFrame;80 81 - (UInt32) frameCount;82 - (void) setFrameCount:(UInt32)frameCount;83 84 - (unsigned) loopCount;85 - (void) setLoopCount:(unsigned)loopCount;86 87 // ========================================88 // Audio access89 // ========================================90 - (unsigned) completedLoops;91 92 - (SInt64) totalFrames;93 - (SInt64) currentFrame;94 - (SInt64) framesRemaining;95 96 - (BOOL) supportsSeeking;97 - (SInt64) seekToFrame:(SInt64)frame;98 99 55 - (SInt64) framesScheduled; 100 56 - (SInt64) framesRendered; 101 57 102 @end103 104 // ========================================105 // AudioScheduler methods106 // ========================================107 @interface ScheduledAudioRegion (AudioSchedulerMethods)108 58 - (unsigned) numberOfSlicesInBuffer; 109 59 - (unsigned) numberOfFramesPerSlice; … … 113 63 - (void) clearSlice:(unsigned)sliceIndex; 114 64 115 - (void) reset;116 117 65 - (void) clearFramesScheduled; 118 66 - (void) clearFramesRendered; 119 67 120 - (UInt32) readAudio:(AudioBufferList *)bufferList frameCount:(UInt32)frameCount;121 68 - (UInt32) readAudioInSlice:(unsigned)sliceIndex; 122 69 … … 126 73 - (void) scheduledAdditionalFrames:(UInt32)frameCount; 127 74 - (void) renderedAdditionalFrames:(UInt32)frameCount; 128 129 - (BOOL) atEnd;130 75 @end -
trunk/Audio/ScheduledAudioRegion.m
r1025 r1043 130 130 #pragma mark Creation 131 131 132 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder 133 { 134 AudioTimeStamp startTime = { 0 }; 135 136 startTime.mFlags = kAudioTimeStampSampleTimeValid; 137 startTime.mSampleTime = 0; 138 139 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:0 frameCount:[decoder totalFrames] loopCount:0]; 140 } 141 142 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startingFrame:(SInt64)startingFrame 143 { 144 AudioTimeStamp startTime = { 0 }; 145 146 startTime.mFlags = kAudioTimeStampSampleTimeValid; 147 startTime.mSampleTime = 0; 148 149 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:startingFrame frameCount:([decoder totalFrames] - startingFrame) loopCount:0]; 150 } 151 152 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount 153 { 154 AudioTimeStamp startTime = { 0 }; 155 156 startTime.mFlags = kAudioTimeStampSampleTimeValid; 157 startTime.mSampleTime = 0; 158 159 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:startingFrame frameCount:frameCount loopCount:0]; 160 } 161 162 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount loopCount:(unsigned)loopCount 163 { 164 AudioTimeStamp startTime = { 0 }; 165 166 startTime.mFlags = kAudioTimeStampSampleTimeValid; 167 startTime.mSampleTime = 0; 168 169 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:startingFrame frameCount:frameCount loopCount:loopCount]; 170 } 171 172 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime 173 { 174 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:0 frameCount:[decoder totalFrames] loopCount:0]; 175 } 176 177 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime startingFrame:(SInt64)startingFrame 178 { 179 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:startingFrame frameCount:([decoder totalFrames] - startingFrame) loopCount:0]; 180 } 181 182 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount 183 { 184 return [ScheduledAudioRegion scheduledAudioRegionForDecoder:decoder startTime:startTime startingFrame:startingFrame frameCount:frameCount loopCount:0]; 185 } 186 187 + (ScheduledAudioRegion *) scheduledAudioRegionForDecoder:(AudioDecoder *)decoder startTime:(AudioTimeStamp)startTime startingFrame:(SInt64)startingFrame frameCount:(unsigned)frameCount loopCount:(unsigned)loopCount 188 { 189 ScheduledAudioRegion *result = [[ScheduledAudioRegion alloc] init]; 190 191 [result setDecoder:decoder]; 192 [result setStartTime:startTime]; 193 [result setStartingFrame:startingFrame]; 194 [result setFrameCount:frameCount]; 195 [result setLoopCount:loopCount]; 196 197 if(0 != [result startingFrame]) 198 [result reset]; 199 200 return [result autorelease]; 132 + (ScheduledAudioRegion *) scheduledAudioRegionWithDecoder:(id <AudioDecoderMethods>)decoder 133 { 134 return [[[ScheduledAudioRegion alloc] initWithDecoder:decoder] autorelease]; 135 } 136 137 + (ScheduledAudioRegion *) scheduledAudioRegionWithDecoder:(id <AudioDecoderMethods>)decoder startTime:(AudioTimeStamp)startTime 138 { 139 return [[[ScheduledAudioRegion alloc] initWithDecoder:decoder startTime:startTime] autorelease]; 140 } 141 142 - (id) initWithDecoder:(id <AudioDecoderMethods>)decoder 143 { 144 if((self = [super init])) { 145 AudioTimeStamp startTime = { 0 }; 146 147 startTime.mFlags = kAudioTimeStampSampleTimeValid; 148 startTime.mSampleTime = 0; 149 150 [self setDecoder:decoder]; 151 [self setStartTime:startTime]; 152 } 153 return self; 154 } 155 156 - (id) initWithDecoder:(id <AudioDecoderMethods>)decoder startTime:(AudioTimeStamp)startTime 157 { 158 if((self = [super init])) { 159 [self setDecoder:decoder]; 160 [self setStartTime:startTime]; 161 } 162 return self; 201 163 } 202 164 … … 221 183 } 222 184 223 - ( AudioDecoder *) decoder{ return [[_decoder retain] autorelease]; }224 225 - (void) setDecoder:( AudioDecoder *)decoder185 - (id <AudioDecoderMethods>) decoder { return [[_decoder retain] autorelease]; } 186 187 - (void) setDecoder:(id <AudioDecoderMethods>)decoder 226 188 { 227 189 NSParameterAssert(nil != decoder); … … 233 195 } 234 196 235 - (unsigned) loopCount { return _loopCount; }236 - (void) setLoopCount:(unsigned)loopCount { _loopCount = loopCount; }237 238 - (SInt64) startingFrame { return _startingFrame; }239 240 - (void) setStartingFrame:(SInt64)startingFrame241 {242 NSParameterAssert(0 <= startingFrame);243 244 _startingFrame = startingFrame;245 }246 247 - (UInt32) frameCount { return _frameCount; }248 249 - (void) setFrameCount:(UInt32)frameCount250 {251 NSParameterAssert(0 < frameCount);252 253 _frameCount = frameCount;254 }255 256 #pragma mark Playback257 258 - (unsigned) completedLoops { return _completedLoops; }259 260 - (SInt64) totalFrames { return (([self loopCount] + 1) * [self frameCount]); }261 - (SInt64) currentFrame { return _totalFramesRead; }262 - (SInt64) framesRemaining { return ([self totalFrames] - [self currentFrame]); }263 264 - (BOOL) supportsSeeking { return [[self decoder] supportsSeeking]; }265 266 - (SInt64) seekToFrame:(SInt64)frame267 {268 NSParameterAssert(0 <= frame && frame < [self totalFrames]);269 270 _completedLoops = frame / [self frameCount];271 _framesReadInCurrentLoop = frame % [self frameCount];272 _totalFramesRead = frame;273 _atEnd = NO;274 275 [[self decoder] seekToFrame:[self startingFrame] + _framesReadInCurrentLoop];276 277 return [self currentFrame];278 }279 280 197 - (SInt64) framesScheduled { return _framesScheduled; } 281 198 - (SInt64) framesRendered { return _framesRendered; } 282 283 - (NSString *) description284 {285 return [NSString stringWithFormat:@"%@ (%qi, %qi)", [self decoder], [self framesRendered], [self framesScheduled]];286 }287 288 @end289 290 @implementation ScheduledAudioRegion (AudioSchedulerMethods)291 199 292 200 - (unsigned) numberOfSlicesInBuffer … … 326 234 } 327 235 328 - (void) reset329 {330 [[self decoder] seekToFrame:[self startingFrame]];331 332 _framesReadInCurrentLoop = 0;333 _totalFramesRead = 0;334 _completedLoops = 0;335 _atEnd = NO;336 }337 338 236 - (void) clearFramesScheduled { _framesScheduled = 0; } 339 237 - (void) clearFramesRendered { _framesRendered = 0; } 340 238 341 - (UInt32) readAudio:(AudioBufferList *)bufferList frameCount:(UInt32)frameCount342 {343 NSParameterAssert(NULL != bufferList);344 NSParameterAssert(0 < frameCount);345 346 if([self loopCount] < [self completedLoops])347 return 0;348 349 UInt32 framesRemaining = [self startingFrame] + [self frameCount] - [[self decoder] currentFrame];350 UInt32 framesToRead = (frameCount < framesRemaining ? frameCount : framesRemaining);351 UInt32 framesRead = 0;352 353 if(0 < framesToRead)354 framesRead = [[self decoder] readAudio:bufferList frameCount:framesToRead];355 356 _framesReadInCurrentLoop += framesRead;357 _totalFramesRead += framesRead;358 359 if([self frameCount] == _framesReadInCurrentLoop || (0 == framesRead && 0 != framesToRead)) {360 ++_completedLoops;361 _framesReadInCurrentLoop = 0;362 363 if([self loopCount] < [self completedLoops])364 _atEnd = YES;365 else366 [[self decoder] seekToFrame:[self startingFrame]];367 }368 369 return framesRead;370 }371 372 239 - (UInt32) readAudioInSlice:(unsigned)sliceIndex 373 240 { 374 241 NSParameterAssert(sliceIndex < [self numberOf
