Compare commits

..

7 Commits

Author SHA1 Message Date
Thong Nguyen e805e4740c More Spectrum Analyzer work 2014-04-24 18:22:40 +01:00
Thong Nguyen 484285df84 Started work on Spectrum Analyzer 2014-04-23 18:03:23 +01:00
Thong Nguyen a9dfb2eddf Fixed thread related crashes in OutputRenderCallback 2014-04-07 15:28:34 +01:00
Thong Nguyen 3fcf054a23 Fix STKAudioPlayer.progress property thread-related crash 2014-04-07 15:15:36 +01:00
Thong Nguyen a615419404 Fixed deployment target min should be 4.3 not 6.0 2014-04-05 13:15:43 +01:00
Thong Nguyen e43a4613f8 startInternal now cleans up audio resources when the playback thread is finished. Added fix for undefned DBL_MAX 2014-04-05 13:08:58 +01:00
Thong Nguyen ca928dfe1e Removed buffering work (now in different branch) 2014-03-24 16:32:38 +00:00
11 changed files with 217 additions and 458 deletions
@@ -27,6 +27,7 @@
A17FFB6318A0028300BAA7FF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A17FFB6218A0028300BAA7FF /* AudioToolbox.framework */; };
A17FFB6918A002E400BAA7FF /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F5E491189EB3F20070B03F /* AVFoundation.framework */; };
A1EBEE64188DE34500681B04 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1EBEE63188DE34500681B04 /* SystemConfiguration.framework */; };
A1F3410A1908185900CA7755 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F341091908185900CA7755 /* Accelerate.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -65,6 +66,7 @@
A142571C18907861005F0129 /* airplane.aac */ = {isa = PBXFileReference; lastKnownFileType = file; path = airplane.aac; sourceTree = "<group>"; };
A17FFB6218A0028300BAA7FF /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
A1EBEE63188DE34500681B04 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
A1F341091908185900CA7755 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
A1F5E48F189EB3CB0070B03F /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
A1F5E491189EB3F20070B03F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
@@ -74,6 +76,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1F3410A1908185900CA7755 /* Accelerate.framework in Frameworks */,
A17FFB6918A002E400BAA7FF /* AVFoundation.framework in Frameworks */,
A17FFB6318A0028300BAA7FF /* AudioToolbox.framework in Frameworks */,
A1EBEE64188DE34500681B04 /* SystemConfiguration.framework in Frameworks */,
@@ -119,6 +122,7 @@
A1115933188D686000641365 /* Frameworks */ = {
isa = PBXGroup;
children = (
A1F341091908185900CA7755 /* Accelerate.framework */,
A17FFB6218A0028300BAA7FF /* AudioToolbox.framework */,
A1F5E491189EB3F20070B03F /* AVFoundation.framework */,
A1F5E48F189EB3CB0070B03F /* AudioUnit.framework */,
@@ -365,7 +369,7 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -403,7 +407,7 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../StreamingKit/StreamingKit",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
+29 -1
View File
@@ -40,6 +40,9 @@
///
@interface AudioPlayerView()
{
NSMutableArray* meters;
}
-(void) setupTimer;
-(void) updateControls;
@end
@@ -55,6 +58,8 @@
{
self.audioPlayer = audioPlayerIn;
self.audioPlayer.spectrumAnalyzerEnabled = YES;
CGSize size = CGSizeMake(220, 50);
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
@@ -114,9 +119,23 @@
statusLabel.textAlignment = NSTextAlignmentCenter;
meters = [[NSMutableArray alloc] init];
meter = [[UIView alloc] initWithFrame:CGRectMake(0, 450, 0, 20)];
meter.backgroundColor = [UIColor greenColor];
for (int i = 0; i < 256; i++)
{
UIView* freqMeter = [[UIView alloc] initWithFrame:CGRectMake(i, self.bounds.size.height, 1, 0)];
freqMeter.backgroundColor = [UIColor blueColor];
[self addSubview:freqMeter];
[meters addObject:freqMeter];
[self sendSubviewToBack:freqMeter];
}
[self addSubview:slider];
[self addSubview:playButton];
@@ -193,9 +212,18 @@
statusLabel.text = audioPlayer.state == STKAudioPlayerStateBuffering ? @"buffering" : @"";
CGFloat newWidth = 320 * (([audioPlayer averagePowerInDecibelsForChannel:1] + 60) / 60);
CGFloat newWidth = 320 * (([audioPlayer testPowerWithIndex:100] + 96) / 96);
meter.frame = CGRectMake(0, 460, newWidth, 20);
for (int i = 0; i < 256; i++)
{
UIView* freqMeter = [meters objectAtIndex:i];
CGFloat height = 200 * (([audioPlayer testPowerWithIndex:i] + 96) / 96);
freqMeter.frame = CGRectMake(freqMeter.frame.origin.x, self.bounds.size.height - height, 1, height);
}
}
-(void) playFromHTTPButtonTouched
@@ -7,8 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
A1682FA318B3903900F29FEC /* STKBufferingDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1682FA218B3903900F29FEC /* STKBufferingDataSource.m */; };
A168C6F118BB67DC003D170D /* STKBufferChunk.m in Sources */ = {isa = PBXBuildFile; fileRef = A168C6F018BB67DC003D170D /* STKBufferChunk.m */; };
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4996A189E744400E2A2E2 /* Cocoa.framework */; };
A1A49975189E744500E2A2E2 /* StreamingKitMac.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A49974189E744500E2A2E2 /* StreamingKitMac.m */; };
A1A4997B189E744500E2A2E2 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4D9188D57F60010896F /* XCTest.framework */; };
@@ -39,6 +37,8 @@
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FA188D5E550010896F /* STKDataSourceWrapper.m */; };
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FC188D5E550010896F /* STKHTTPDataSource.m */; };
A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */; };
A1F341041908183300CA7755 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F341031908183300CA7755 /* Accelerate.framework */; };
A1F341081908183A00CA7755 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1F341071908183A00CA7755 /* Accelerate.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -85,10 +85,6 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
A1682FA118B3903900F29FEC /* STKBufferingDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKBufferingDataSource.h; sourceTree = "<group>"; };
A1682FA218B3903900F29FEC /* STKBufferingDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKBufferingDataSource.m; sourceTree = "<group>"; };
A168C6EF18BB67DC003D170D /* STKBufferChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKBufferChunk.h; sourceTree = "<group>"; };
A168C6F018BB67DC003D170D /* STKBufferChunk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKBufferChunk.m; sourceTree = "<group>"; };
A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStreamingKitMac.a; sourceTree = BUILT_PRODUCTS_DIR; };
A1A4996A189E744400E2A2E2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; };
A1A4996D189E744500E2A2E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -131,6 +127,8 @@
A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKLocalFileDataSource.h; sourceTree = "<group>"; };
A1E7C4FE188D5E550010896F /* STKLocalFileDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKLocalFileDataSource.m; sourceTree = "<group>"; };
A1E7C507188D62D20010896F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
A1F341031908183300CA7755 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
A1F341071908183A00CA7755 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -138,6 +136,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1F341081908183A00CA7755 /* Accelerate.framework in Frameworks */,
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -156,6 +155,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1F341041908183300CA7755 /* Accelerate.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -254,6 +254,8 @@
A1E7C4CA188D57F50010896F /* Frameworks */ = {
isa = PBXGroup;
children = (
A1F341071908183A00CA7755 /* Accelerate.framework */,
A1F341031908183300CA7755 /* Accelerate.framework */,
A1A499F6189E79EA00E2A2E2 /* AudioToolbox.framework */,
A1C9767618981BFE0057F881 /* AudioUnit.framework */,
A1E7C507188D62D20010896F /* UIKit.framework */,
@@ -272,10 +274,6 @@
A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */,
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */,
A1E7C4F4188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m */,
A168C6EF18BB67DC003D170D /* STKBufferChunk.h */,
A168C6F018BB67DC003D170D /* STKBufferChunk.m */,
A1682FA118B3903900F29FEC /* STKBufferingDataSource.h */,
A1682FA218B3903900F29FEC /* STKBufferingDataSource.m */,
A1E7C4F5188D5E550010896F /* STKCoreFoundationDataSource.h */,
A1E7C4F6188D5E550010896F /* STKCoreFoundationDataSource.m */,
A1E7C4F7188D5E550010896F /* STKDataSource.h */,
@@ -512,9 +510,7 @@
A1BF65D2189A6582004DD08C /* STKQueueEntry.m in Sources */,
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */,
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */,
A1682FA318B3903900F29FEC /* STKBufferingDataSource.m in Sources */,
A1E7C502188D5E550010896F /* STKDataSource.m in Sources */,
A168C6F118BB67DC003D170D /* STKBufferChunk.m in Sources */,
A1BF65D5189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m in Sources */,
A1E7C500188D5E550010896F /* STKAutoRecoveringHTTPDataSource.m in Sources */,
);
@@ -674,7 +670,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
@@ -705,7 +701,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
@@ -146,6 +146,8 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
@property (readwrite) BOOL meteringEnabled;
/// Enables or disables the EQ
@property (readwrite) BOOL equalizerEnabled;
/// Enables or disables the spectrum analyzer (fft)
@property (readwrite) BOOL spectrumAnalyzerEnabled;
/// Returns an array of STKFrameFilterEntry objects representing the filters currently in use
@property (readonly) NSArray* frameFilters;
/// Returns the items pending to be played (includes buffering and upcoming items but does not include the current item)
@@ -263,4 +265,6 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// Sets the gain value (from -96 low to +24 high) for an equalizer band (0 based index)
-(void) setGain:(float)gain forEqualizerBand:(int)bandIndex;
-(float) testPowerWithIndex:(int)index;
@end
+154 -13
View File
@@ -40,8 +40,13 @@
#import "STKQueueEntry.h"
#import "NSMutableArray+STKAudioPlayer.h"
#import "libkern/OSAtomic.h"
#include <Accelerate/Accelerate.h>
#import <float.h>
#ifndef DBL_MAX
#define DBL_MAX 1.7976931348623157e+308
#endif
#pragma mark Defines
#define kOutputBus 0
@@ -185,6 +190,7 @@ static AudioStreamBasicDescription canonicalAudioStreamBasicDescription;
BOOL meteringEnabled;
BOOL equalizerOn;
BOOL equalizerEnabled;
BOOL spectrumAnalyzerEnabled;
STKAudioPlayerOptions options;
NSMutableArray* converterNodes;
@@ -249,6 +255,14 @@ static AudioStreamBasicDescription canonicalAudioStreamBasicDescription;
pthread_mutex_t mainThreadSyncCallMutex;
pthread_cond_t mainThreadSyncCallReadyCondition;
float* window;
float* obtainedReal;
float* originalReal;
int fftStride;
FFTSetup setupReal;
DSPSplitComplex fftInput;
volatile BOOL waiting;
volatile double requestedSeekTime;
volatile BOOL disposeWasRequested;
@@ -466,6 +480,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
self->volume = 1.0;
self->equalizerEnabled = optionsIn.equalizerBandFrequencies[0] != 0;
self->spectrumAnalyzerEnabled = NO;
PopulateOptionsWithDefault(&options);
@@ -526,7 +541,12 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
{
currentlyPlayingEntry.dataSource.delegate = nil;
[currentlyReadingEntry.dataSource unregisterForEvents];
OSSpinLockLock(&currentEntryReferencesLock);
currentlyPlayingEntry = nil;
OSSpinLockUnlock(&currentEntryReferencesLock);
}
[self stopAudioUnitWithReason:STKAudioPlayerStopReasonDisposed];
@@ -569,6 +589,9 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
pthread_cond_destroy(&mainThreadSyncCallReadyCondition);
free(readBuffer);
free(originalReal);
free(obtainedReal);
free(window);
}
-(void) startSystemBackgroundTask
@@ -924,20 +947,15 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
}
OSSpinLockLock(&currentEntryReferencesLock);
STKQueueEntry* entry = currentlyPlayingEntry;
OSSpinLockUnlock(&currentEntryReferencesLock);
if (entry == nil)
{
OSSpinLockUnlock(&currentEntryReferencesLock);
return 0;
return 0;
}
double retval = [entry duration];
OSSpinLockUnlock(&currentEntryReferencesLock);
double progress = [self progress];
if (retval < progress && retval > 0)
@@ -960,7 +978,9 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
return 0;
}
OSSpinLockLock(&currentEntryReferencesLock);
STKQueueEntry* entry = currentlyPlayingEntry;
OSSpinLockUnlock(&currentEntryReferencesLock);
if (entry == nil)
{
@@ -1347,7 +1367,6 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
}
}
pthread_mutex_unlock(&playerMutex);
return YES;
}
@@ -1398,6 +1417,8 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
playbackThreadRunLoop = nil;
[self destroyAudioResources];
[threadFinishedCondLock lock];
[threadFinishedCondLock unlockWithCondition:1];
}
@@ -2530,11 +2551,15 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
{
STKAudioPlayer* audioPlayer = (__bridge STKAudioPlayer*)inRefCon;
OSSpinLockLock(&audioPlayer->currentEntryReferencesLock);
STKQueueEntry* entry = audioPlayer->currentlyPlayingEntry;
STKQueueEntry* currentlyReadingEntry = audioPlayer->currentlyReadingEntry;
OSSpinLockUnlock(&audioPlayer->currentEntryReferencesLock);
OSSpinLockLock(&audioPlayer->pcmBufferSpinLock);
BOOL waitForBuffer = NO;
BOOL muted = audioPlayer->muted;
STKQueueEntry* entry = audioPlayer->currentlyPlayingEntry;
AudioBuffer* audioBuffer = audioPlayer->pcmAudioBuffer;
UInt32 frameSizeInBytes = audioPlayer->pcmBufferFrameSizeInBytes;
UInt32 used = audioPlayer->pcmBufferUsedFrameCount;
@@ -2552,10 +2577,10 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
if (entry->lastFrameQueued >= 0)
{
framesRequiredToStartPlaying = MIN(framesRequiredToStartPlaying, audioPlayer->currentlyPlayingEntry->lastFrameQueued);
framesRequiredToStartPlaying = MIN(framesRequiredToStartPlaying, entry->lastFrameQueued);
}
if (entry && audioPlayer->currentlyReadingEntry == entry
if (entry && currentlyReadingEntry == entry
&& entry->framesQueued < framesRequiredToStartPlaying)
{
waitForBuffer = YES;
@@ -2765,13 +2790,19 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
{
pthread_mutex_lock(&audioPlayer->playerMutex);
if (lastFramePlayed && entry == audioPlayer->currentlyPlayingEntry)
OSSpinLockLock(&audioPlayer->currentEntryReferencesLock);
STKQueueEntry* currentlyPlayingEntry = audioPlayer->currentlyPlayingEntry;
OSSpinLockUnlock(&audioPlayer->currentEntryReferencesLock);
if (lastFramePlayed && entry == currentlyPlayingEntry)
{
[audioPlayer audioQueueFinishedPlaying:entry];
while (extraFramesPlayedNotAssigned > 0)
{
OSSpinLockLock(&audioPlayer->currentEntryReferencesLock);
STKQueueEntry* newEntry = audioPlayer->currentlyPlayingEntry;
OSSpinLockUnlock(&audioPlayer->currentEntryReferencesLock);
if (newEntry != nil)
{
@@ -2895,6 +2926,115 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
return averagePowerDb[channelNumber];
}
-(BOOL) spectrumAnalyzerEnabled
{
return self->spectrumAnalyzerEnabled;
}
-(void) setSpectrumAnalyzerEnabled:(BOOL)value
{
if (self->spectrumAnalyzerEnabled == value)
{
return;
}
self->spectrumAnalyzerEnabled = value;
if (!value)
{
[self removeFrameFilterWithName:@"STKSpectrumAnalyzerFilter"];
}
else
{
if (!obtainedReal)
{
int maxSamples = 4096;
int log2n = log2f(maxSamples);
int n = 1 << log2n;
fftStride = 1;
int nOver2 = maxSamples / 2;
fftInput.realp = (float*)calloc(nOver2, sizeof(float));
fftInput.imagp =(float*)calloc(nOver2, sizeof(float));
obtainedReal = (float*)calloc(n, sizeof(float));
originalReal = (float*)calloc(n, sizeof(float));
window = (float*)calloc(maxSamples, sizeof(float));
vDSP_blkman_window(window, maxSamples, 0);
setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);
}
[self appendFrameFilterWithName:@"STKSpectrumAnalyzerFilter" block:^(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames)
{
int log2n = log2f(frameCount);
int n = 1 << log2n;
int nOver2 = frameCount / 2;
SInt16* samples16 = (SInt16*)frames;
SInt32* samples32 = (SInt32*)frames;
if (bytesPerFrame / channelsPerFrame == 2)
{
for (int i = 0, j = 0; i < frameCount * channelsPerFrame; i+= channelsPerFrame, j += 2)
{
originalReal[j] = samples16[i] / 32768.0;
}
}
else if (bytesPerFrame / channelsPerFrame == 4)
{
for (int i = 0, j = 0; i < frameCount * channelsPerFrame; i+= channelsPerFrame, j+= 2)
{
originalReal[j] = samples32[i] / 32768.0;
}
}
vDSP_hann_window(window, n, 0);
vDSP_vmul(originalReal, 2, window, 1, originalReal, 2, n);
vDSP_ctoz((COMPLEX*)originalReal, 2, &fftInput, 1, nOver2);
vDSP_fft_zrip(setupReal, &fftInput, fftStride, log2n, FFT_FORWARD);
float one = 1;
float scale = (float)1.0 / (2 * n);
vDSP_vsmul(fftInput.realp, 1, &scale, fftInput.realp, 1, nOver2);
vDSP_vsmul(fftInput.imagp, 1, &scale, fftInput.imagp, 1, nOver2);
pthread_mutex_lock(&self->playerMutex);
vDSP_zvmags(&fftInput, 1, obtainedReal, 1, nOver2);
vDSP_vdbcon(obtainedReal, 1, &one, obtainedReal, 1, nOver2, 0);
float vmin = -96;
float vmax = 0;
vDSP_vclip(obtainedReal, 1, &vmin, &vmax, obtainedReal, 1, nOver2);
pthread_mutex_unlock(&self->playerMutex);
}];
}
}
-(float) testPowerWithIndex:(int)index
{
pthread_mutex_lock(&self->playerMutex);
if (!obtainedReal)
{
pthread_mutex_unlock(&self->playerMutex);
return 0;
}
float retval = obtainedReal[index];
pthread_mutex_unlock(&self->playerMutex);
return retval;
}
-(BOOL) meteringEnabled
{
return self->meteringEnabled;
@@ -2924,11 +3064,12 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
{
return;
}
self->meteringEnabled = value;
if (!value)
{
[self removeFrameFilterWithName:@"STKMeteringFilter"];
self->meteringEnabled = NO;
}
else
{
@@ -1,25 +0,0 @@
//
// STKBufferChunk.h
// StreamingKit
//
// Created by Thong Nguyen on 24/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface STKBufferChunk : NSObject
{
@public
UInt32 index;
UInt32 size;
UInt32 position;
UInt8* buffer;
}
@property (readonly) UInt32 absoluteStart;
@property (readonly) UInt32 absolutePosition;
-(id) initWithBufferSize:(UInt32)sizeIn;
@end
@@ -1,40 +0,0 @@
//
// STKBufferChunk.m
// StreamingKit
//
// Created by Thong Nguyen on 24/02/2014.
// Copyright (c) 2014 Thong Nguyen. All rights reserved.
//
#import "STKBufferChunk.h"
@implementation STKBufferChunk
-(id) initWithBufferSize:(UInt32)sizeIn
{
if (self = [super init])
{
self->size = sizeIn;
self->buffer = calloc(sizeof(UInt8), sizeIn);
}
return self;
}
-(void) dealloc
{
free(self->buffer);
}
-(UInt32) absoluteStart
{
return self->index * self->size;
}
-(UInt32) absolutePosition
{
return self.absoluteStart + self->position;
}
@end
@@ -1,44 +0,0 @@
/**********************************************************************************
STKBufferingDataSource.h
Created by Thong Nguyen on 16/10/2012.
https://github.com/tumtumtum/audjustable
Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Thong Nguyen (tumtumtum@gmail.com)
4. Neither the name of Thong Nguyen nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**********************************************************************************/
#import "STKDataSource.h"
@interface STKBufferingDataSource : STKDataSource
@property (readonly) SInt64 position;
@property (readonly) SInt64 length;
-(id) initWithDataSource:(STKDataSource*)dataSourceIn withMaxSize:(int)maxSizeIn;
@end
@@ -1,319 +0,0 @@
/**********************************************************************************
STKBufferingDataSource.m
Created by Thong Nguyen on 16/10/2012.
https://github.com/tumtumtum/audjustable
Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Thong Nguyen (tumtumtum@gmail.com)
4. Neither the name of Thong Nguyen nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**********************************************************************************/
#import "STKBufferingDataSource.h"
#import "STKBufferChunk.h"
#import <pthread.h>
#define STK_BUFFER_CHUNK_SIZE (128 * 1024)
@interface STKBufferingDataSource()
{
@private
NSRunLoop* runLoop;
SInt32 maxSize;
UInt32 chunkSize;
UInt32 chunkCount;
SInt64 position;
pthread_mutex_t mutex;
pthread_cond_t condition;
STKBufferChunk* __strong * bufferChunks;
STKDataSource* dataSource;
}
@end
@interface STKBufferingDataSourceThread : NSThread
{
@private
NSRunLoop* runLoop;
NSConditionLock* threadStartedLock;
}
@end
@implementation STKBufferingDataSourceThread
-(id) init
{
if (self = [super init])
{
threadStartedLock = [[NSConditionLock alloc] initWithCondition:0];
}
return self;
}
-(NSRunLoop*) runLoop
{
[threadStartedLock lockWhenCondition:1];
[threadStartedLock unlockWithCondition:0];
return self->runLoop;
}
-(void) main
{
runLoop = [NSRunLoop currentRunLoop];
[threadStartedLock lockWhenCondition:0];
[threadStartedLock unlockWithCondition:1];
[runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
while (true)
{
NSDate* date = [[NSDate alloc] initWithTimeIntervalSinceNow:10];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:date];
}
}
@end
static STKBufferingDataSourceThread* thread;
@implementation STKBufferingDataSource
+(void) initialize
{
thread = [[STKBufferingDataSourceThread alloc] init];
[thread start];
}
-(id) initWithDataSource:(STKDataSource*)dataSourceIn withMaxSize:(int)maxSizeIn
{
if (self = [super init])
{
self->maxSize = maxSizeIn;
self->dataSource = dataSourceIn;
self->chunkSize = STK_BUFFER_CHUNK_SIZE;
self->dataSource.delegate = self.delegate;
[self->dataSource registerForEvents:[thread runLoop]];
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&self->mutex, &attr);
pthread_cond_init(&self->condition, NULL);
}
return self;
}
-(void) dealloc
{
self->dataSource.delegate = nil;
for (int i = 0; i < self->chunkCount; i++)
{
self->bufferChunks[i] = nil;
}
free(self->bufferChunks);
pthread_mutex_destroy(&self->mutex);
pthread_cond_destroy(&self->condition);
}
-(void) createBuffer
{
if (self->bufferChunks == nil)
{
int length = (int)MIN(self.length == 0? 1024 * 1024 : self.length, self->maxSize);
self->chunkCount = (int)((length / self->chunkSize) + 1);
self->bufferChunks = (__strong STKBufferChunk**)calloc(sizeof(STKBufferChunk*), self->chunkCount);
}
}
-(STKBufferChunk*) chunkForPosition:(SInt64)positionIn createIfNotExist:(BOOL)createIfNotExist
{
int chunkIndex = (int)(positionIn / chunkCount);
if (self->bufferChunks[chunkIndex] == nil && createIfNotExist)
{
self->bufferChunks[chunkIndex] = [[STKBufferChunk alloc] initWithBufferSize:STK_BUFFER_CHUNK_SIZE];
}
return self->bufferChunks[chunkIndex];
}
-(SInt64) length
{
return self->dataSource.length;
}
-(void) seekToOffset:(SInt64)offset
{
pthread_mutex_lock(&mutex);
[self seekToNextGap];
pthread_mutex_unlock(&mutex);
}
-(BOOL) hasBytesAvailable
{
return NO;
}
-(int) readIntoBuffer:(UInt8*)bufferIn withSize:(int)size
{
return 0;
}
-(void) invokeBlockOnEventsRunLoop:(void(^)())block
{
if (!runLoop)
{
return;
}
block = [block copy];
CFRunLoopPerformBlock(runLoop.getCFRunLoop, NSRunLoopCommonModes, ^
{
if ([self hasBytesAvailable])
{
block();
}
});
CFRunLoopWakeUp(runLoop.getCFRunLoop);
}
-(BOOL) registerForEvents:(NSRunLoop*)runLoopIn
{
runLoop = runLoopIn;
[dataSource registerForEvents:[thread runLoop]];
return YES;
}
-(void) unregisterForEvents
{
runLoop = nil;
[dataSource unregisterForEvents];
}
-(void) close
{
[dataSource unregisterForEvents];
[dataSource close];
}
-(void) seekToNextGap
{
int startChunkIndex = (int)(self->position / chunkCount);
for (int i = 0; i < self->chunkCount; i++)
{
int chunkIndex = (i + startChunkIndex) % self->chunkCount;
STKBufferChunk* chunk = self->bufferChunks[chunkIndex];
if (chunk == nil)
{
chunk = [[STKBufferChunk alloc] initWithBufferSize:STK_BUFFER_CHUNK_SIZE];
chunk->index = chunkIndex;
self->bufferChunks[chunkIndex] = chunk;
}
if (chunk->position < chunk->size)
{
[dataSource seekToOffset:(self->chunkSize * chunk->index) + chunk->position];
}
}
}
-(void) dataSourceDataAvailable:(STKDataSource*)dataSourceIn
{
if (![dataSourceIn hasBytesAvailable])
{
return;
}
pthread_mutex_lock(&mutex);
if (self->bufferChunks == nil)
{
[self createBuffer];
}
SInt64 sourcePosition = dataSourceIn.position;
STKBufferChunk* chunk = [self chunkForPosition:sourcePosition createIfNotExist:YES];
if (chunk->position >= chunk->size)
{
[self seekToNextGap];
return;
}
int offset = dataSourceIn.position % self->chunkSize;
if (offset >= chunk->position)
{
[self seekToNextGap];
return;
}
int bytesToRead = self->chunkSize - offset;
int bytesRead = [dataSourceIn readIntoBuffer:(chunk->buffer + offset) withSize:bytesToRead];
chunk->position = offset + bytesRead;
pthread_mutex_unlock(&mutex);
}
-(void) dataSourceErrorOccured:(STKDataSource*)dataSourceIn
{
[self.delegate dataSourceErrorOccured:self];
}
-(void) dataSourceEof:(STKDataSource*)dataSourceIn
{
}
@end
@@ -200,6 +200,18 @@
[self open];
}
if (stream == 0)
{
CFRunLoopPerformBlock(eventsRunLoop.getCFRunLoop, NSRunLoopCommonModes, ^
{
[self errorOccured];
});
CFRunLoopWakeUp(eventsRunLoop.getCFRunLoop);
return;
}
if (CFReadStreamSetProperty(stream, kCFStreamPropertyFileCurrentOffset, (__bridge CFTypeRef)[NSNumber numberWithLongLong:offset]) != TRUE)
{
position = 0;
@@ -18,6 +18,8 @@
{
if (self = [super init])
{
self->spinLock = OS_SPINLOCK_INIT;
self.dataSource = dataSourceIn;
self.queueItemId = queueItemIdIn;
self->lastFrameQueued = -1;