Browse Source

Adds threading. Uses whole sound

master
Joshua Moerman 10 years ago
parent
commit
4b80ab096e
  1. 58
      SpectogramPrototype.xcodeproj/project.pbxproj
  2. 5
      SpectogramPrototype/AppDelegate.m
  3. 10
      SpectogramPrototype/AudioFile.m
  4. 19
      SpectogramPrototype/Base.lproj/Main_iPad.storyboard
  5. 2
      SpectogramPrototype/FFTTest.h
  6. 2
      SpectogramPrototype/FFTTest.m
  7. 5
      SpectogramPrototype/RuledScrollView.m
  8. 2
      SpectogramPrototype/Spectographer.h
  9. 41
      SpectogramPrototype/Spectographer.m
  10. 3
      SpectogramPrototype/ViewController.h
  11. 72
      SpectogramPrototype/ViewController.m

58
SpectogramPrototype.xcodeproj/project.pbxproj

@ -25,10 +25,6 @@
4261F08818671ECD00AA0EF9 /* ContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4261F08718671ECD00AA0EF9 /* ContentView.xib */; }; 4261F08818671ECD00AA0EF9 /* ContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4261F08718671ECD00AA0EF9 /* ContentView.xib */; };
426665B51869A7CC005D62AC /* RuledScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 426665B41869A7CC005D62AC /* RuledScrollView.m */; }; 426665B51869A7CC005D62AC /* RuledScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 426665B41869A7CC005D62AC /* RuledScrollView.m */; };
426665B81869CEFE005D62AC /* FFTTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 426665B71869CEFE005D62AC /* FFTTest.m */; }; 426665B81869CEFE005D62AC /* FFTTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 426665B71869CEFE005D62AC /* FFTTest.m */; };
426665BA1869CF73005D62AC /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665B91869CF73005D62AC /* Accelerate.framework */; };
426665BC1869EF4B005D62AC /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665BB1869EF4B005D62AC /* CoreAudio.framework */; };
426665C11869F194005D62AC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665C01869F194005D62AC /* AudioToolbox.framework */; };
426665C51869F50B005D62AC /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 426665C41869F50B005D62AC /* MediaPlayer.framework */; };
42ABF54B187035F900B20D82 /* Spectographer.m in Sources */ = {isa = PBXBuildFile; fileRef = 42ABF54A187035F900B20D82 /* Spectographer.m */; }; 42ABF54B187035F900B20D82 /* Spectographer.m in Sources */ = {isa = PBXBuildFile; fileRef = 42ABF54A187035F900B20D82 /* Spectographer.m */; };
42E12A91186F122400866CB3 /* testMusic.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 42E12A90186F122400866CB3 /* testMusic.mp3 */; }; 42E12A91186F122400866CB3 /* testMusic.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 42E12A90186F122400866CB3 /* testMusic.mp3 */; };
42E12A94186F1F4C00866CB3 /* AudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E12A93186F1F4C00866CB3 /* AudioFile.m */; }; 42E12A94186F1F4C00866CB3 /* AudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E12A93186F1F4C00866CB3 /* AudioFile.m */; };
@ -70,10 +66,6 @@
426665B41869A7CC005D62AC /* RuledScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuledScrollView.m; sourceTree = "<group>"; }; 426665B41869A7CC005D62AC /* RuledScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuledScrollView.m; sourceTree = "<group>"; };
426665B61869CEFE005D62AC /* FFTTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FFTTest.h; sourceTree = "<group>"; }; 426665B61869CEFE005D62AC /* FFTTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FFTTest.h; sourceTree = "<group>"; };
426665B71869CEFE005D62AC /* FFTTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FFTTest.m; sourceTree = "<group>"; }; 426665B71869CEFE005D62AC /* FFTTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FFTTest.m; sourceTree = "<group>"; };
426665B91869CF73005D62AC /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
426665BB1869EF4B005D62AC /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
426665C01869F194005D62AC /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
426665C41869F50B005D62AC /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
42ABF549187035F900B20D82 /* Spectographer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Spectographer.h; sourceTree = "<group>"; }; 42ABF549187035F900B20D82 /* Spectographer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Spectographer.h; sourceTree = "<group>"; };
42ABF54A187035F900B20D82 /* Spectographer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Spectographer.m; sourceTree = "<group>"; }; 42ABF54A187035F900B20D82 /* Spectographer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Spectographer.m; sourceTree = "<group>"; };
42E12A90186F122400866CB3 /* testMusic.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = testMusic.mp3; sourceTree = "<group>"; }; 42E12A90186F122400866CB3 /* testMusic.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = testMusic.mp3; sourceTree = "<group>"; };
@ -86,10 +78,6 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
426665C51869F50B005D62AC /* MediaPlayer.framework in Frameworks */,
426665C11869F194005D62AC /* AudioToolbox.framework in Frameworks */,
426665BC1869EF4B005D62AC /* CoreAudio.framework in Frameworks */,
426665BA1869CF73005D62AC /* Accelerate.framework in Frameworks */,
424F84AB18661F8000687D3B /* CoreGraphics.framework in Frameworks */, 424F84AB18661F8000687D3B /* CoreGraphics.framework in Frameworks */,
424F84AD18661F8000687D3B /* UIKit.framework in Frameworks */, 424F84AD18661F8000687D3B /* UIKit.framework in Frameworks */,
424F84A918661F8000687D3B /* Foundation.framework in Frameworks */, 424F84A918661F8000687D3B /* Foundation.framework in Frameworks */,
@ -132,10 +120,6 @@
424F84A718661F8000687D3B /* Frameworks */ = { 424F84A718661F8000687D3B /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
426665C41869F50B005D62AC /* MediaPlayer.framework */,
426665C01869F194005D62AC /* AudioToolbox.framework */,
426665BB1869EF4B005D62AC /* CoreAudio.framework */,
426665B91869CF73005D62AC /* Accelerate.framework */,
424F84A818661F8000687D3B /* Foundation.framework */, 424F84A818661F8000687D3B /* Foundation.framework */,
424F84AA18661F8000687D3B /* CoreGraphics.framework */, 424F84AA18661F8000687D3B /* CoreGraphics.framework */,
424F84AC18661F8000687D3B /* UIKit.framework */, 424F84AC18661F8000687D3B /* UIKit.framework */,
@ -372,30 +356,48 @@
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
); );
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_PEDANTIC = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0; IPHONEOS_DEPLOYMENT_TARGET = 7.0;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
@ -412,23 +414,43 @@
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_PEDANTIC = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0; IPHONEOS_DEPLOYMENT_TARGET = 7.0;
RUN_CLANG_STATIC_ANALYZER = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;

5
SpectogramPrototype/AppDelegate.m

@ -9,7 +9,8 @@
#import "AppDelegate.h" #import "AppDelegate.h"
@implementation AppDelegate @implementation AppDelegate
@synthesize window;
/* Commented out to silence warnings!
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ {
// Override point for customization after application launch. // Override point for customization after application launch.
@ -42,5 +43,5 @@
{ {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
} }
*/
@end @end

10
SpectogramPrototype/AudioFile.m

@ -7,7 +7,7 @@
// //
#import "AudioFile.h" #import "AudioFile.h"
#import <AudioToolbox/ExtendedAudioFile.h> @import AudioToolbox.ExtendedAudioFile;
@interface AudioFile (){ @interface AudioFile (){
ExtAudioFileRef audioFile; ExtAudioFileRef audioFile;
@ -76,14 +76,14 @@
short * buffer = bufferList.mBuffers[0].mData; short * buffer = bufferList.mBuffers[0].mData;
float * leftEnd = left + nSamples; float * leftEnd = left + nSamples;
for(unsigned int i = 0; i < nFrames; ++i){ for(unsigned int i = 0; i < nFrames; ++i){
*left++ = *buffer++ / 32768.0; *left++ = *buffer++ / 32768.0f;
*right++ = *buffer++ / 32768.0; *right++ = *buffer++ / 32768.0f;
} }
// assume left and right are of the same size // assume left and right are of the same size
while(left != leftEnd){ while(left != leftEnd){
*left++ = 0.0; *left++ = 0;
*right++ = 0.0; *right++ = 0;
} }
free(bufferList.mBuffers[0].mData); free(bufferList.mBuffers[0].mData);

19
SpectogramPrototype/Base.lproj/Main_iPad.storyboard

@ -21,8 +21,8 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="0.40000000600000002" green="1" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.40000000600000002" green="1" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/>
</scrollView> </scrollView>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kj8-JR-vKG"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kj8-JR-vKG">
<rect key="frame" x="200" y="300" width="111" height="42"/> <rect key="frame" x="20" y="40" width="60" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="22"/> <fontDescription key="fontDescription" type="system" pointSize="22"/>
<state key="normal" title="Media"> <state key="normal" title="Media">
@ -32,12 +32,27 @@
<action selector="mediaButtonPressed:" destination="DUW-zh-mwd" eventType="touchUpInside" id="hZd-Q2-HcR"/> <action selector="mediaButtonPressed:" destination="DUW-zh-mwd" eventType="touchUpInside" id="hZd-Q2-HcR"/>
</connections> </connections>
</button> </button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FQ1-hk-Tya">
<rect key="frame" x="100" y="40" width="108" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="22"/>
<state key="normal" title="Reset View">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="resetView:" destination="DUW-zh-mwd" eventType="touchUpInside" id="xv9-4L-1Ve"/>
</connections>
</button>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints> <constraints>
<constraint firstItem="kj8-JR-vKG" firstAttribute="top" secondItem="n1Z-VL-Qbf" secondAttribute="bottom" constant="20" id="0K2-Le-fIA"/>
<constraint firstAttribute="trailing" secondItem="chg-BV-Ue8" secondAttribute="trailing" id="0fj-54-kGr"/> <constraint firstAttribute="trailing" secondItem="chg-BV-Ue8" secondAttribute="trailing" id="0fj-54-kGr"/>
<constraint firstItem="FQ1-hk-Tya" firstAttribute="centerY" secondItem="kj8-JR-vKG" secondAttribute="centerY" id="JB3-Mj-mXd"/>
<constraint firstItem="chg-BV-Ue8" firstAttribute="top" secondItem="hed-94-g1X" secondAttribute="top" id="OzJ-ZW-YG0"/> <constraint firstItem="chg-BV-Ue8" firstAttribute="top" secondItem="hed-94-g1X" secondAttribute="top" id="OzJ-ZW-YG0"/>
<constraint firstItem="kj8-JR-vKG" firstAttribute="leading" secondItem="hed-94-g1X" secondAttribute="leading" constant="20" id="QYP-WV-LmJ"/>
<constraint firstAttribute="bottom" secondItem="chg-BV-Ue8" secondAttribute="bottom" id="Sc7-ra-bZs"/> <constraint firstAttribute="bottom" secondItem="chg-BV-Ue8" secondAttribute="bottom" id="Sc7-ra-bZs"/>
<constraint firstItem="FQ1-hk-Tya" firstAttribute="leading" secondItem="kj8-JR-vKG" secondAttribute="trailing" constant="20" id="X8X-id-l6J"/>
<constraint firstItem="chg-BV-Ue8" firstAttribute="leading" secondItem="hed-94-g1X" secondAttribute="leading" id="vH2-JI-XSk"/> <constraint firstItem="chg-BV-Ue8" firstAttribute="leading" secondItem="hed-94-g1X" secondAttribute="leading" id="vH2-JI-XSk"/>
</constraints> </constraints>
</view> </view>

2
SpectogramPrototype/FFTTest.h

@ -10,5 +10,5 @@
@interface FFTTest : NSObject @interface FFTTest : NSObject
- (void) inPlaceFFT:(float*)data forSize:(unsigned int)n; - (void) inPlaceFFT:(float*)data forSize:(unsigned int)n;
@property (readonly) unsigned int acceptedSize; @property (nonatomic, readonly) unsigned int acceptedSize;
@end @end

2
SpectogramPrototype/FFTTest.m

@ -7,7 +7,7 @@
// //
#import "FFTTest.h" #import "FFTTest.h"
#import <Accelerate/Accelerate.h> @import Accelerate;
@interface FFTTest () { @interface FFTTest () {
FFTSetup setup; FFTSetup setup;

5
SpectogramPrototype/RuledScrollView.m

@ -69,7 +69,7 @@
- (void)placeTicks { - (void)placeTicks {
[topRuler.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; [topRuler.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
CGFloat spacing = 600.0f; CGFloat spacing = 600.0f;
for (CGFloat x = rulerWidth + 0.5*spacing; x < topRuler.frame.size.width; x += spacing){ for (CGFloat x = rulerWidth + 0.5f*spacing; x < topRuler.frame.size.width; x += spacing){
UIView * line = [[UIView alloc] initWithFrame:CGRectMake(x, 0, 1, rulerHeight)]; UIView * line = [[UIView alloc] initWithFrame:CGRectMake(x, 0, 1, rulerHeight)];
line.backgroundColor = [UIColor blackColor]; line.backgroundColor = [UIColor blackColor];
[topRuler addSubview:line]; [topRuler addSubview:line];
@ -83,6 +83,7 @@
} }
- (void)layoutSubviews { - (void)layoutSubviews {
[super layoutSubviews];
{ {
CGRect frame = self.topRuler.frame; CGRect frame = self.topRuler.frame;
frame.origin.y = self.contentOffset.y; frame.origin.y = self.contentOffset.y;
@ -103,7 +104,7 @@
leftRuler.frame = CGRectMake(0, 0, rulerWidth, contentSize.height + rulerHeight); leftRuler.frame = CGRectMake(0, 0, rulerWidth, contentSize.height + rulerHeight);
} }
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{ - (UIView *)viewForZoomingInScrollView:(UIScrollView *)__unused scrollView{
return content; return content;
} }

2
SpectogramPrototype/Spectographer.h

@ -11,6 +11,6 @@
@interface Spectographer : NSObject @interface Spectographer : NSObject
- (void)openAudioFile:(NSURL*)url; - (void)openAudioFile:(NSURL*)url;
- (CGImageRef)generate; - (void)generate:(void (^)(CGImageRef))callback;
@end @end

41
SpectogramPrototype/Spectographer.m

@ -10,10 +10,10 @@
#import "FFTTest.h" #import "FFTTest.h"
#import "AudioFile.h" #import "AudioFile.h"
UInt8 clamp_to_uint8(float x){ uint8_t clamp_to_uint8(float x){
if(x >= 1.0) return 255; if(x >= 1.0) return 255;
if(x <= 0.0) return 0; if(x <= 0.0) return 0;
return 255.0 * x; return (uint8_t)(255.0f * x);
} }
@interface Spectographer (){ @interface Spectographer (){
@ -22,7 +22,8 @@ UInt8 clamp_to_uint8(float x){
float * left; float * left;
float * right; float * right;
} }
- (void)threadTask:(void (^)(CGImageRef))callback;
- (CGImageRef)singleStep CF_RETURNS_RETAINED;
@end @end
@implementation Spectographer @implementation Spectographer
@ -41,25 +42,43 @@ UInt8 clamp_to_uint8(float x){
assert(audioFile); assert(audioFile);
} }
- (CGImageRef)generate{ - (void)generate:(void (^)(CGImageRef))callback{
[NSThread detachNewThreadSelector:@selector(threadTask:) toTarget:self withObject:callback];
}
- (void)threadTask:(void (^)(CGImageRef))callback{
CGImageRef cgImage = nil;
while((cgImage = [self singleStep])){
callback(cgImage);
CGImageRelease(cgImage);
}
}
- (CGImageRef)singleStep{
unsigned int size = FFTHandler.acceptedSize; unsigned int size = FFTHandler.acceptedSize;
unsigned int width = size/4; unsigned int width = 128;
unsigned int height = size/8; unsigned int height = size/8;
char * rgba = calloc(width*height*4, sizeof(char)); uint8_t * rgba = calloc(width*height*4, sizeof(uint8_t));
for(unsigned int x = 0; x < width; ++x){ unsigned int x = 0;
[audioFile fillLeft:left andRight:right withNumberOfSamples:size]; for(; x < width; ++x){
if(![audioFile fillLeft:left andRight:right withNumberOfSamples:size])
break;
[FFTHandler inPlaceFFT:left forSize:size]; [FFTHandler inPlaceFFT:left forSize:size];
[FFTHandler inPlaceFFT:right forSize:size]; [FFTHandler inPlaceFFT:right forSize:size];
for(unsigned int y = 0; y < height; ++y){ for(unsigned int y = 0; y < height; ++y){
unsigned int yy = height - y - 1; unsigned int yy = height - y - 1;
rgba[4*width*yy + 4*x + 0] = clamp_to_uint8(100.0 * left[y]); rgba[4*width*yy + 4*x + 0] = clamp_to_uint8(100.0f * left[y]);
rgba[4*width*yy + 4*x + 1] = clamp_to_uint8(100.0 * right[y]); rgba[4*width*yy + 4*x + 1] = clamp_to_uint8(100.0f * right[y]);
rgba[4*width*yy + 4*x + 2] = clamp_to_uint8(10.0 * (left[y] + right[y])); rgba[4*width*yy + 4*x + 2] = clamp_to_uint8(10.0f * (left[y] + right[y]));
rgba[4*width*yy + 4*x + 3] = 0; rgba[4*width*yy + 4*x + 3] = 0;
} }
} }
if(!x){
free(rgba);
return nil;
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
assert(colorSpace); assert(colorSpace);

3
SpectogramPrototype/ViewController.h

@ -15,6 +15,7 @@
@property (nonatomic) IBOutlet RuledScrollView * scrollView; @property (nonatomic) IBOutlet RuledScrollView * scrollView;
@property (nonatomic) IBOutlet UIView * contentView; @property (nonatomic) IBOutlet UIView * contentView;
- (IBAction) mediaButtonPressed:(UIButton*)sender; - (IBAction)mediaButtonPressed:(UIButton*)sender;
- (IBAction)resetView:(id)sender;
@end @end

72
SpectogramPrototype/ViewController.m

@ -6,8 +6,7 @@
// Copyright (c) 2013 Joshua Moerman. All rights reserved. // Copyright (c) 2013 Joshua Moerman. All rights reserved.
// //
#import <MediaPlayer/MPMediaPickerController.h> @import MediaPlayer.MPMediaPickerController;
#import <AudioToolbox/ExtendedAudioFile.h>
#import "ViewController.h" #import "ViewController.h"
#import "RuledScrollView.h" #import "RuledScrollView.h"
@ -40,8 +39,11 @@ device get_device(){
@interface ViewController () <MPMediaPickerControllerDelegate> { @interface ViewController () <MPMediaPickerControllerDelegate> {
Spectographer * spectographer; Spectographer * spectographer;
UIPopoverController * pop; UIPopoverController * pop;
NSMutableArray * slices;
} }
- (void) openAudioFile:(NSURL*)filePath; - (void)openAudioFile:(NSURL*)filePath;
- (void)addSlice:(UIImageView*)view;
- (void)removeAllSlices;
@property (nonatomic, strong) UILabel* header; @property (nonatomic, strong) UILabel* header;
@end @end
@ -58,6 +60,10 @@ device get_device(){
contentView.autoresizingMask = UIViewAutoresizingNone; contentView.autoresizingMask = UIViewAutoresizingNone;
scrollView.contentSize = contentView.bounds.size; scrollView.contentSize = contentView.bounds.size;
} }
if(!slices){
slices = [[NSMutableArray alloc] init];
}
} }
- (void)didReceiveMemoryWarning{ - (void)didReceiveMemoryWarning{
@ -65,26 +71,58 @@ device get_device(){
} }
- (void)openAudioFile:(NSURL *)filePath{ - (void)openAudioFile:(NSURL *)filePath{
[self removeAllSlices];
if(!spectographer) if(!spectographer)
spectographer = [[Spectographer alloc] init]; spectographer = [[Spectographer alloc] init];
[spectographer openAudioFile:filePath]; [spectographer openAudioFile:filePath];
CGImageRef image = [spectographer generate]; [spectographer generate:^void(CGImageRef image){
CGImageRetain(image);
UIImage * newUIImage = [UIImage imageWithCGImage:image]; dispatch_async(dispatch_get_main_queue(), ^{
assert(newUIImage); UIImage * newUIImage = [UIImage imageWithCGImage:image];
assert(newUIImage);
CGImageRelease(image);
UIImageView * view = [[UIImageView alloc] initWithImage:newUIImage];
[self addSlice:view];
});
}];
CGImageRelease(image); // [contentView removeFromSuperview];
// contentView = view;
// scrollView.zoomScale = 1.0;
//
// [scrollView.content addSubview:contentView];
// contentView.autoresizingMask = UIViewAutoresizingNone;
// scrollView.contentSize = contentView.bounds.size;
}
- (void)addSlice:(UIImageView *)view{
if(slices.count){
UIImageView * lastSlice = slices.lastObject;
float x = CGRectGetMaxX(lastSlice.frame);
view.frame = CGRectOffset(view.frame, x, 0);
} // else leave the origin at 0
UIImageView * view = [[UIImageView alloc] initWithImage:newUIImage]; [contentView addSubview:view];
[slices addObject:view];
[contentView removeFromSuperview]; UIImageView * lastSlice = slices.lastObject;
contentView = view; scrollView.contentSize = CGSizeMake(CGRectGetMaxX(lastSlice.frame), CGRectGetMaxY(lastSlice.frame));
}
- (void)removeAllSlices{
for(UIView * view in slices){
[view removeFromSuperview];
}
[slices removeAllObjects];
scrollView.contentSize = CGSizeZero;
}
- (void)resetView:(id)__unused sender{
scrollView.zoomScale = 1.0; scrollView.zoomScale = 1.0;
UIImageView * lastSlice = slices.lastObject;
[scrollView.content addSubview:contentView]; scrollView.contentSize = CGSizeMake(CGRectGetMaxX(lastSlice.frame), CGRectGetMaxY(lastSlice.frame));
contentView.autoresizingMask = UIViewAutoresizingNone;
scrollView.contentSize = contentView.bounds.size;
} }
- (void)mediaButtonPressed:(UIButton*)sender{ - (void)mediaButtonPressed:(UIButton*)sender{
@ -128,11 +166,15 @@ device get_device(){
} }
[pop dismissPopoverAnimated:YES]; [pop dismissPopoverAnimated:YES];
pop = nil; pop = nil;
[mediaPicker dismissViewControllerAnimated:YES completion:nil];
} }
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker { - (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
[pop dismissPopoverAnimated:YES]; [pop dismissPopoverAnimated:YES];
pop = nil; pop = nil;
[mediaPicker dismissViewControllerAnimated:YES completion:nil];
} }
@end @end