├── .gitignore ├── LICENSE ├── README.md ├── Ultrasound.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── appdev.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── Ultrasound ├── AppDelegate.h ├── AppDelegate.m ├── AudioManager.h ├── AudioManager.mm ├── AudioPlayer.h ├── AudioPlayer.m ├── CADebugMacros.cpp ├── CADebugMacros.h ├── CAMath.h ├── CAStreamBasicDescription.cpp ├── CAStreamBasicDescription.h ├── CAXException.cpp ├── CAXException.h ├── CardIO │ ├── CardIO.h │ ├── CardIOCreditCardInfo.h │ ├── CardIOPaymentViewController.h │ ├── CardIOPaymentViewControllerDelegate.h │ └── libCardIO.a ├── Clump.h ├── Clump.m ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── FFTAccelerate.cpp ├── FFTAccelerate.h ├── FFTBufferManager.cpp ├── FFTBufferManager.h ├── FFTBufferManager.mm ├── FFTGraphView.h ├── FFTGraphView.m ├── GraphView.h ├── GraphView.m ├── GraphViewUtils.h ├── GraphViewUtils.m ├── NSArray+Levenshtein.h ├── NSArray+Levenshtein.m ├── NSData+AES256.h ├── NSData+AES256.m ├── NSString+Levenshtein.h ├── NSString+Levenshtein.m ├── ProcessAlgoMain.h ├── ProcessAlgoMain.m ├── ProcessingFunctions.h ├── ProcessingFunctions.m ├── ProcessingFunctionsC.cpp ├── ProcessingFunctionsC.h ├── Processor.h ├── Processor.m ├── ReceiveViewController.h ├── ReceiveViewController.m ├── SpectrumAnalysis.cpp ├── SpectrumAnalysis.h ├── Test Strings.plist ├── Transforms.h ├── TransmitGraphView.h ├── TransmitGraphView.m ├── TransmitViewController.h ├── TransmitViewController.m ├── UIView+Donald.h ├── UIView+Donald.m ├── Ultrasound-Info.plist ├── Ultrasound-Prefix.pch ├── audio_helper.cpp ├── audio_helper.h ├── ding.wav ├── en.lproj │ ├── InfoPlist.strings │ ├── MainStoryboard_iPad.storyboard │ └── MainStoryboard_iPhone.storyboard ├── iOS7ProgressView.h ├── iOS7ProgressView.m ├── main.m ├── rad2fft.c └── rad2fft.h └── UltrasoundTests ├── UltrasoundTests-Info.plist ├── UltrasoundTests.h ├── UltrasoundTests.m └── en.lproj └── InfoPlist.strings /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 davisappdev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libultrasound-ios 2 | ================= 3 | 4 | Objective-C library and demo app for secure communication via ultrasound. 5 | -------------------------------------------------------------------------------- /Ultrasound.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Ultrasound.xcodeproj/project.xcworkspace/xcuserdata/appdev.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisappdev/libultrasound-ios/f0d669354a984d9b769cf6818dadb6e6eaaaba56/Ultrasound.xcodeproj/project.xcworkspace/xcuserdata/appdev.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Ultrasound/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Ultrasound/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Ultrasound/AudioManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AudioManager.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define kTransmitFrequencies @[@16990, @17420, @17851, @18282, @18712, @19143, @19574, @20004] 12 | #define kNumberOfTransmitFrequencies 8 13 | #define kPacketDelimiterFrequency 19003 14 | #define kRatio (21.533203125) 15 | 16 | 17 | @protocol AudioManagerDelegate 18 | 19 | - (void) renderAudioIntoData:(Float32 *)data withSampleRate:(double)sampleRate numberOfFrames:(int)numberOfFrames; 20 | - (void) fftData:(float *)data arraySize:(int)size cutoff:(float)cutoff; 21 | 22 | @end 23 | 24 | @interface AudioManager : NSObject 25 | 26 | 27 | - (void) startAudio; 28 | - (void) stopAudio; 29 | - (void) toggleAudio; 30 | 31 | - (id) initWithDelegate:(id)delegate; 32 | 33 | - (NSArray *) fourier:(NSArray *) requestedFrequencies; 34 | 35 | 36 | @property (nonatomic, strong) id delegate; 37 | @property (nonatomic) BOOL isReceiving; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Ultrasound/AudioManager.mm: -------------------------------------------------------------------------------- 1 | // 2 | // AudioManager.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | 10 | #import "AudioManager.h" 11 | #import 12 | #include "CAStreamBasicDescription.h" 13 | #include "audio_helper.h" 14 | #include "FFTBufferManager.h" 15 | #include "ProcessingFunctionsC.h" 16 | 17 | @implementation AudioManager 18 | { 19 | AudioUnit toneUnit; 20 | AURenderCallbackStruct inputProc; 21 | CAStreamBasicDescription thruFormat; 22 | FFTBufferManager *fft; 23 | int32_t *fftData; 24 | 25 | } 26 | 27 | const double kSampleRate = 44100; 28 | 29 | static AudioManager *globalSelf; 30 | 31 | 32 | void SilenceData(AudioBufferList *inData) 33 | { 34 | for (UInt32 i=0; i < inData->mNumberBuffers; i++) 35 | memset(inData->mBuffers[i].mData, 0, inData->mBuffers[i].mDataByteSize); 36 | } 37 | 38 | 39 | 40 | OSStatus RenderTone( 41 | void *inRefCon, 42 | AudioUnitRenderActionFlags *ioActionFlags, 43 | const AudioTimeStamp *inTimeStamp, 44 | UInt32 inBusNumber, 45 | UInt32 inNumberFrames, 46 | AudioBufferList *ioData) 47 | 48 | { 49 | if(globalSelf.isReceiving) 50 | { 51 | AudioUnitRender(globalSelf->toneUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, ioData); 52 | 53 | if (globalSelf->fft == NULL) 54 | { 55 | return noErr; 56 | } 57 | if (globalSelf->fft->NeedsNewAudioData()) 58 | { 59 | globalSelf->fft->GrabAudioData(ioData); 60 | } 61 | } 62 | else 63 | { 64 | Float32 *ptr = (Float32 *)(ioData->mBuffers[0].mData); 65 | [globalSelf.delegate renderAudioIntoData:ptr withSampleRate:kSampleRate numberOfFrames:inNumberFrames]; 66 | } 67 | 68 | // SilenceData(ioData); 69 | return noErr; 70 | } 71 | 72 | 73 | void ToneInterruptionListener(void *inClientData, UInt32 inInterruptionState) 74 | { 75 | [globalSelf stopAudio]; 76 | } 77 | 78 | 79 | int SetupRemoteIO (AudioUnit& inRemoteIOUnit, AURenderCallbackStruct inRenderProc, CAStreamBasicDescription& outFormat) 80 | { 81 | // Open the output unit 82 | AudioComponentDescription desc; 83 | desc.componentType = kAudioUnitType_Output; 84 | desc.componentSubType = kAudioUnitSubType_RemoteIO; 85 | desc.componentManufacturer = kAudioUnitManufacturer_Apple; 86 | desc.componentFlags = 0; 87 | desc.componentFlagsMask = 0; 88 | 89 | AudioComponent comp = AudioComponentFindNext(NULL, &desc); 90 | 91 | AudioComponentInstanceNew(comp, &inRemoteIOUnit); 92 | 93 | UInt32 one = 1; 94 | AudioUnitSetProperty(inRemoteIOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one)); 95 | AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &inRenderProc, sizeof(inRenderProc)); 96 | 97 | //set our required format - Canonical AU format: LPCM non-interleaved 8.24 fixed point 98 | outFormat.SetAUCanonical(2, false); 99 | outFormat.mSampleRate = kSampleRate; 100 | // AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outFormat, sizeof(outFormat)); 101 | AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outFormat, sizeof(outFormat)); 102 | 103 | 104 | AudioUnitInitialize(inRemoteIOUnit); 105 | 106 | return 0; 107 | } 108 | 109 | 110 | 111 | - (void) toggleAudio 112 | { 113 | if (toneUnit) 114 | { 115 | [self stopAudio]; 116 | } 117 | else 118 | { 119 | [self startAudio]; 120 | } 121 | } 122 | 123 | 124 | - (void) stopAudio 125 | { 126 | AudioOutputUnitStop(toneUnit); 127 | AudioUnitUninitialize(toneUnit); 128 | AudioComponentInstanceDispose(toneUnit); 129 | toneUnit = nil; 130 | } 131 | 132 | 133 | - (void) startAudio 134 | { 135 | Float32 preferredBufferSize = .005; 136 | AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize); 137 | 138 | inputProc.inputProc = RenderTone; 139 | inputProc.inputProcRefCon = (__bridge void *)(self); 140 | 141 | SetupRemoteIO(toneUnit, inputProc, thruFormat); 142 | 143 | UInt32 maxFPS; 144 | UInt32 size = sizeof(maxFPS); 145 | AudioUnitGetProperty(toneUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, &size); 146 | fft = new FFTBufferManager(maxFPS); 147 | 148 | fftData = new int32_t[maxFPS / 2]; 149 | fourierSize = maxFPS / 2; 150 | 151 | // Start playback 152 | AudioOutputUnitStart(toneUnit); 153 | } 154 | 155 | int fourierSize; 156 | float delimCutoff; 157 | - (id) initWithDelegate:(id)delegate 158 | { 159 | self = [super init]; 160 | 161 | if(self) 162 | { 163 | self.delegate = delegate; 164 | 165 | globalSelf = self; 166 | delimCutoff = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? 25 : 80; 167 | 168 | OSStatus result = AudioSessionInitialize(NULL, NULL, ToneInterruptionListener, (__bridge void *)(self)); 169 | if (result == kAudioSessionNoError) 170 | { 171 | UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord; 172 | UInt32 one = 1; 173 | AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory); 174 | AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(one), &one); 175 | } 176 | AudioSessionSetActive(true); 177 | 178 | } 179 | return self; 180 | } 181 | 182 | 183 | - (id) init 184 | { 185 | return [self initWithDelegate:nil]; 186 | } 187 | 188 | 189 | #define CLAMP(min,x,max) (x < min ? min : (x > max ? max : x)) 190 | 191 | void printFFT(float *fftData) 192 | { 193 | for(int i = 0; i < 1024; i++) 194 | { 195 | printf("%d,%f\n", i, fftData[i]); 196 | } 197 | printf("\n"); 198 | } 199 | 200 | 201 | BOOL shouldPrintNormal = NO; 202 | BOOL shouldPrintInterp = NO; 203 | void printFFTStuff(int32_t *fftData) 204 | { 205 | int maxY = 1024; 206 | for (int y = 0; y < maxY - 1; y++) 207 | { 208 | CGFloat yFract = (CGFloat) y / (CGFloat)(maxY - 1); 209 | CGFloat fftIdx = yFract * ((CGFloat) fourierSize); 210 | 211 | double fftIdx_i, fftIdx_f; 212 | fftIdx_f = modf(fftIdx, &fftIdx_i); 213 | 214 | SInt8 fft_l, fft_r; 215 | CGFloat fft_l_fl, fft_r_fl; 216 | CGFloat interpVal; 217 | fft_l = (fftData[(int)fftIdx_i] & 0xFF000000) >> 24; 218 | if(shouldPrintNormal) 219 | { 220 | printf("%d,%d\n", y, fft_l); 221 | } 222 | fft_r = (fftData[(int)fftIdx_i + 1] & 0xFF000000) >> 24; 223 | fft_l_fl = (CGFloat)(fft_l + 80) / 64.; 224 | fft_r_fl = (CGFloat)(fft_r + 80) / 64.; 225 | interpVal = fft_l_fl * (1. - fftIdx_f) + fft_r_fl * fftIdx_f; 226 | 227 | interpVal = CLAMP(0., interpVal, 1.); 228 | interpVal *= 120; 229 | 230 | if(shouldPrintInterp) 231 | { 232 | printf("%d,%f\n", y, interpVal); 233 | } 234 | 235 | } 236 | } 237 | 238 | 239 | 240 | 241 | #define kSTDCutoffCoefficient 3.0 242 | - (NSArray *) fourier:(NSArray *) requestedFrequencies 243 | { 244 | fft->ComputeFFT(fftData); 245 | 246 | int y, maxY; 247 | maxY = 1024; 248 | 249 | printFFTStuff(fftData); 250 | 251 | float *storedFFTData = (float *)malloc(sizeof(float) * (maxY-1)); 252 | for (y = 0; y < maxY - 1; y++) 253 | { 254 | CGFloat yFract = (CGFloat) y / (CGFloat)(maxY - 1); 255 | CGFloat fftIdx = yFract * ((CGFloat) fourierSize); 256 | 257 | double fftIdx_i, fftIdx_f; 258 | fftIdx_f = modf(fftIdx, &fftIdx_i); 259 | 260 | SInt8 fft_l, fft_r; 261 | CGFloat fft_l_fl, fft_r_fl; 262 | CGFloat interpVal; 263 | fft_l = (fftData[(int)fftIdx_i] & 0xFF000000) >> 24; 264 | fft_r = (fftData[(int)fftIdx_i + 1] & 0xFF000000) >> 24; 265 | fft_l_fl = (CGFloat)(fft_l + 80) / 64.; 266 | fft_r_fl = (CGFloat)(fft_r + 80) / 64.; 267 | interpVal = fft_l_fl * (1. - fftIdx_f) + fft_r_fl * fftIdx_f; 268 | 269 | interpVal = CLAMP(0., interpVal, 1.); 270 | interpVal *= 120; 271 | 272 | storedFFTData[y] = interpVal; 273 | } 274 | 275 | 276 | 277 | int minIndex = round([requestedFrequencies[0] intValue] / kRatio) - 20; 278 | int maxIndex = round([[requestedFrequencies lastObject] intValue] / kRatio) + 20; 279 | int delimIndex = round(kPacketDelimiterFrequency / kRatio); 280 | 281 | /* for(int i = minIndex; i <= maxIndex; i++) 282 | { 283 | printf("%d,%f\n", i - minIndex, storedFFTData[i]); 284 | }*/ 285 | 286 | double delimValue = 0; 287 | int delimUp = 3; 288 | int delimDown = 3; 289 | for(int j = delimIndex; j <= delimIndex + delimUp; j++) 290 | { 291 | double a = storedFFTData[j]; 292 | delimValue = MAX(delimValue, a); 293 | } 294 | for(int j = delimIndex; j >= delimIndex - delimDown; j--) 295 | { 296 | double a = storedFFTData[j]; 297 | delimValue = MAX(delimValue, a); 298 | } 299 | 300 | // double averageValueInUltraSonicRange = meanOfArray(storedFFTData, 0, maxY - 1); 301 | 302 | minIndex = MAX(0, minIndex); 303 | maxIndex = MIN(maxIndex, maxY-2); 304 | double standardDeviation = meanlessStandardDeviation(storedFFTData, minIndex, maxIndex); 305 | double maxValue = maxValueForArray(storedFFTData, minIndex, maxIndex); 306 | double cutoffValue = maxValue - (standardDeviation * kSTDCutoffCoefficient); 307 | cutoffValue = MIN(cutoffValue, 40); 308 | 309 | [self.delegate fftData:storedFFTData arraySize:maxY-1 cutoff:cutoffValue]; 310 | 311 | // printf("AVG: %f\n", averageValueInUltraSonicRange); 312 | // printf("Cutoff Value: %f\n", cutoffValue); 313 | 314 | 315 | NSMutableArray *outputFrequencies = [NSMutableArray array]; 316 | 317 | BOOL allBitsOff = YES; 318 | for(int i = 0; i < requestedFrequencies.count; i++) 319 | { 320 | int index = round([requestedFrequencies[i] intValue] / kRatio); 321 | //NSLog(@"Index: %i", index-minIndex); 322 | 323 | // Calculate the difference neighboring frequency indices. 324 | int dIndexUp = (i == requestedFrequencies.count - 1) ? (index - round([requestedFrequencies[i - 1] intValue] / kRatio)) : (round([requestedFrequencies[i + 1] intValue] / kRatio) - index); 325 | int dIndexDown = (i == 0) ? (round([requestedFrequencies[i+1] intValue] / kRatio) - index) : (index - round([requestedFrequencies[i-1] intValue] / kRatio)); 326 | 327 | int upAmt = MAX(ceilf(dIndexUp / 4.0f) - 1, 2); 328 | int downAmt = MAX(ceilf(dIndexDown / 4.0f) - 1, 2); 329 | 330 | 331 | double val = 0; 332 | for(int j = index; j <= index + upAmt; j++) 333 | { 334 | double a = storedFFTData[j]; 335 | val = MAX(val, a); 336 | } 337 | for(int j = index; j >= index - downAmt; j--) 338 | { 339 | double a = storedFFTData[j]; 340 | val = MAX(val, a); 341 | } 342 | 343 | // printf("%f\n", val); 344 | 345 | if(standardDeviation < 0.5) 346 | { 347 | [outputFrequencies addObject:@(NO)]; 348 | } 349 | else if(val > cutoffValue) 350 | { 351 | [outputFrequencies addObject:@(YES)]; 352 | allBitsOff = NO; 353 | } 354 | else 355 | { 356 | [outputFrequencies addObject:@(NO)]; 357 | } 358 | } 359 | 360 | //printf("%f\n", delimValue); 361 | if(delimValue > delimCutoff && fabs(delimValue - 120) > DBL_EPSILON) 362 | { 363 | // printf("DELIMITER DETECTED\n\n"); 364 | return nil; // Returning nil indicates that the delimiter was detected 365 | } 366 | else 367 | { 368 | // printf("NO DELIMITER\n\n"); 369 | } 370 | 371 | 372 | //printf("\n"); 373 | free(storedFFTData); 374 | return [outputFrequencies copy]; 375 | } 376 | 377 | @end 378 | -------------------------------------------------------------------------------- /Ultrasound/AudioPlayer.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "AudioManager.h" 4 | 5 | 6 | #define kFFTInterval 0.02 7 | #define kTransmitInterval 0.3 // 0.3 8 | 9 | @protocol AudioPlayerReceiveDelegate 10 | 11 | - (void) audioReceivedDataUpdate:(int)data; 12 | - (void) audioReceivedText:(NSString *) text rollingAverage:(float)avg; 13 | - (void) audioReceivedFFTData:(float *)data arraySize:(int)size cutoff:(float)cutoff; 14 | 15 | @end 16 | 17 | @protocol AudioPlayerTransmitDelegate 18 | 19 | - (void) audioStartedTransmittingSequence: (float *) freqs withSize: (int) size; 20 | - (void) audioStartedTransmittingFrequencies:(float *) freqs withSize:(int) size; 21 | - (void) audioFinishedTransmittingSequence; 22 | 23 | @end 24 | 25 | @interface AudioPlayer : NSObject 26 | 27 | + (AudioPlayer *) sharedAudioPlayer; 28 | 29 | - (void) start; 30 | - (void) stop; 31 | - (void) setDataToTransmit: (int) numberToSend; 32 | - (void) transmitSequence:(NSArray *)sequence; 33 | - (void) transmitPacketDelimiterWithCallback:(void (^)(void))callback; 34 | - (void) transmitString:(NSString *)string; 35 | 36 | @property (nonatomic) BOOL isReceiving; 37 | @property (nonatomic, weak) id transmitDelegate; 38 | @property (nonatomic, weak) id receiveDelegate; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Ultrasound/AudioPlayer.m: -------------------------------------------------------------------------------- 1 | // 2 | // AudioPlayer.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 10/21/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import "AudioPlayer.h" 10 | #import "Processor.h" 11 | #import "NSArray+Levenshtein.h" 12 | 13 | @interface AudioPlayer () 14 | { 15 | float *frequenciesToSend; 16 | float *oldTransmittingFrequencies; 17 | } 18 | 19 | @property (nonatomic, strong) AudioManager *audio; 20 | @property (nonatomic) double theta; 21 | @property (nonatomic) double frequency; 22 | @property (nonatomic) BOOL isPlaying; 23 | @property (nonatomic) double t; 24 | @property (nonatomic, strong) NSTimer *FFTTimer; 25 | @property (nonatomic, strong) NSTimer *transmitTimer; 26 | @property BOOL frequenciesChanging; 27 | 28 | @property (nonatomic) int sequenceIndex; 29 | 30 | @property (nonatomic) BOOL isTransmittingDelimiter; 31 | 32 | @property (nonatomic) NSMutableArray *receivedPacketData; 33 | 34 | @property (nonatomic) BOOL recentlyDelimited; 35 | @property (nonatomic) BOOL hasHeardPacketDelimiter; 36 | 37 | @property (nonatomic, strong) NSString *testString; 38 | @end 39 | 40 | @implementation AudioPlayer 41 | 42 | 43 | AudioPlayer *sharedPlayer; 44 | + (AudioPlayer *) sharedAudioPlayer 45 | { 46 | if(sharedPlayer == nil) 47 | { 48 | sharedPlayer = [[AudioPlayer alloc] init]; 49 | } 50 | return sharedPlayer; 51 | } 52 | 53 | - (void) transmitPacketDelimiterWithCallback:(void (^)(void))callback 54 | { 55 | self.isTransmittingDelimiter = YES; 56 | for(int i = 0; i < kNumberOfTransmitFrequencies; i++) 57 | { 58 | frequenciesToSend[i] = 0; 59 | } 60 | 61 | __weak AudioPlayer *weakSelf = self; 62 | double delayInSeconds = 1.0; 63 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 64 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 65 | weakSelf.isTransmittingDelimiter = NO; 66 | if(callback) 67 | { 68 | callback(); 69 | } 70 | }); 71 | } 72 | 73 | - (void) setDataToTransmit: (int) numberToSend 74 | { 75 | self.frequenciesChanging = YES; 76 | 77 | currentFrame = 0; 78 | if(frequenciesToSend != NULL) 79 | { 80 | if(oldTransmittingFrequencies != NULL) 81 | { 82 | free(oldTransmittingFrequencies); 83 | } 84 | oldTransmittingFrequencies = malloc(sizeof(float) * kNumberOfTransmitFrequencies); 85 | 86 | memcpy(oldTransmittingFrequencies, frequenciesToSend, sizeof(float) * kNumberOfTransmitFrequencies); 87 | } 88 | 89 | NSArray *dataToSend = [self convertByteToBoolData:numberToSend]; 90 | NSArray *frequencies = [self frequenciesUsedForTransmitting]; 91 | NSLog(@"%@", dataToSend); 92 | 93 | for (int i = 0; i < dataToSend.count; i++) 94 | { 95 | if ([dataToSend[i] boolValue]) 96 | { 97 | frequenciesToSend[i] = [frequencies[i] floatValue]; 98 | } 99 | else 100 | { 101 | frequenciesToSend[i] = 0.0f; 102 | } 103 | } 104 | 105 | r0 = arc4random(); 106 | r1 = arc4random(); 107 | 108 | self.frequenciesChanging = NO; 109 | [self.transmitDelegate audioStartedTransmittingFrequencies:frequenciesToSend withSize:kNumberOfTransmitFrequencies]; 110 | } 111 | 112 | BOOL first = YES; 113 | - (void) transmitSequence:(NSArray *)sequence 114 | { 115 | NSLog(@"Transmitted nibble sequence: %@", sequence); 116 | [self.transmitDelegate audioStartedTransmittingSequence:frequenciesToSend withSize:kNumberOfTransmitFrequencies]; 117 | 118 | if(first) 119 | { 120 | __weak AudioPlayer *weakSelf = self; 121 | [self transmitPacketDelimiterWithCallback:^{ 122 | weakSelf.sequenceIndex = 0; 123 | weakSelf.transmitTimer = [NSTimer timerWithTimeInterval:kTransmitInterval target:weakSelf selector:@selector(updateTransmitSequence:) userInfo:sequence repeats:YES]; 124 | [[NSRunLoop mainRunLoop] addTimer:weakSelf.transmitTimer forMode:NSRunLoopCommonModes]; 125 | 126 | [weakSelf updateTransmitSequence:weakSelf.transmitTimer]; 127 | }]; 128 | first = NO; 129 | } 130 | else 131 | { 132 | self.sequenceIndex = 0; 133 | self.transmitTimer = [NSTimer timerWithTimeInterval:kTransmitInterval target:self selector:@selector(updateTransmitSequence:) userInfo:sequence repeats:YES]; 134 | [[NSRunLoop mainRunLoop] addTimer:self.transmitTimer forMode:NSRunLoopCommonModes]; 135 | 136 | [self updateTransmitSequence:self.transmitTimer]; 137 | } 138 | } 139 | 140 | - (void) transmitString:(NSString *)string 141 | { 142 | // Encrypt string using key 143 | NSString *key = @"my key"; 144 | // NSArray *nibbles = [Processor encodeStringAndEncrypt:string withKey:key]; 145 | NSArray *nibbles = [Processor encodeString:string]; 146 | [self transmitSequence:nibbles]; 147 | } 148 | 149 | - (void) updateTransmitSequence:(NSTimer *)timer 150 | { 151 | NSArray *seq = timer.userInfo; 152 | if(self.sequenceIndex >= seq.count) 153 | { 154 | [self.transmitTimer invalidate]; 155 | [self transmitPacketDelimiterWithCallback:^{ 156 | [self.transmitDelegate audioFinishedTransmittingSequence]; 157 | // [self stop]; 158 | }]; 159 | return; 160 | } 161 | 162 | int currentData = [seq[self.sequenceIndex] intValue]; 163 | [self setDataToTransmit:currentData]; 164 | 165 | self.sequenceIndex++; 166 | } 167 | 168 | - (id) init 169 | { 170 | self = [super init]; 171 | if(self) 172 | { 173 | self.audio = [[AudioManager alloc] initWithDelegate:self]; 174 | 175 | if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) 176 | { 177 | amplitudeAdjustments = amplitudeAdjustmentsITouchTransmit; 178 | } 179 | else 180 | { 181 | amplitudeAdjustments = amplitudeAdjustmentsIPadTransmit; 182 | } 183 | 184 | frequenciesToSend = malloc(sizeof(float) * kNumberOfTransmitFrequencies); 185 | self.receivedPacketData = [[NSMutableArray alloc] init]; 186 | 187 | 188 | 189 | NSString *path = [[NSBundle mainBundle] pathForResource:@"Test Strings" ofType:@"plist"]; 190 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; 191 | self.testString = dict[@"transmitString"]; 192 | } 193 | 194 | return self; 195 | } 196 | 197 | 198 | double err_s = 0.0; 199 | int err_c = 0; 200 | 201 | - (void) getTransmittedData 202 | { 203 | NSArray *frequenciesToCheck = [self frequenciesUsedForTransmitting]; 204 | NSArray *receivedData = [self.audio fourier:frequenciesToCheck]; 205 | if(receivedData == nil && !self.recentlyDelimited) // Delimiter was detected 206 | { 207 | NSLog(@"Processing packet"); 208 | 209 | // // Print out collected packet 210 | // for(int i = 0; i < self.receivedPacketData.count; i++) 211 | // { 212 | // printf("%d,%d\n", i, [self.receivedPacketData[i] intValue]); 213 | // } 214 | if(self.receivedPacketData.count > 10) 215 | { 216 | NSArray *result = [Processor processPacketData:self.receivedPacketData]; 217 | // NSLog(@"Received nibble sequence: %@", result); 218 | 219 | if(result.count % 2 == 1 && [result[0] intValue] == 0) 220 | { 221 | [(NSMutableArray *)(result = [result mutableCopy]) removeObjectAtIndex:0]; 222 | NSLog(@"Removed first nibble"); 223 | } 224 | 225 | if(result.count > 4) 226 | { 227 | NSArray *correctNibbles = [Processor encodeString:self.testString]; 228 | double error = [correctNibbles percentErrorToReceivedArray:result]; 229 | if(error > 0.8) 230 | { 231 | printf("BAD TRANSMISSION!\n"); 232 | NSLog(@"Should have been nibbles: %@", correctNibbles); 233 | NSLog(@"Received nibbles: %@", result); 234 | NSArray *result = [Processor processPacketData:self.receivedPacketData]; 235 | } 236 | printf("Error = %f\n", error); 237 | if(error == 0) 238 | { 239 | printf("Perfect transmission! :)\n"); 240 | } 241 | err_s += error; 242 | err_c++; 243 | 244 | printf("Error Average = %f\n", err_s / err_c); 245 | } 246 | 247 | NSString *receivedText = [Processor decodeData:result]; 248 | 249 | NSLog(@"%@", receivedText); 250 | [self.receiveDelegate audioReceivedText:receivedText rollingAverage:err_s / err_c]; 251 | } 252 | 253 | [self.receivedPacketData removeAllObjects]; 254 | 255 | self.recentlyDelimited = YES; 256 | self.hasHeardPacketDelimiter = NO; 257 | 258 | return; 259 | } 260 | else if(receivedData != nil && self.recentlyDelimited) 261 | { 262 | self.hasHeardPacketDelimiter = YES; 263 | NSLog(@"Starting packet"); 264 | } 265 | 266 | if(self.hasHeardPacketDelimiter) 267 | { 268 | int byte = (int)[self convertBoolDataToByte:receivedData]; 269 | [self.receiveDelegate audioReceivedDataUpdate:byte]; 270 | [self.receivedPacketData addObject:@(byte)]; 271 | 272 | // NSLog(@"Adding byte to packet array"); 273 | 274 | self.recentlyDelimited = NO; 275 | } 276 | 277 | } 278 | 279 | - (BOOL) isDataAllZero:(NSArray *) data 280 | { 281 | for(int i = 0; i < data.count; i++) 282 | { 283 | if([data[i] boolValue]) 284 | { 285 | return NO; 286 | } 287 | } 288 | 289 | return YES; 290 | } 291 | 292 | - (Byte) convertBoolDataToByte:(NSArray *)data 293 | { 294 | Byte sum = 0; 295 | for(int i = 0; i < data.count; i++) 296 | { 297 | BOOL b = [data[i] boolValue]; 298 | if(b) 299 | { 300 | sum += pow(2, i); 301 | } 302 | } 303 | 304 | return sum; 305 | } 306 | 307 | - (NSArray *) frequenciesUsedForTransmitting 308 | { 309 | return kTransmitFrequencies; 310 | } 311 | 312 | 313 | #define DEBUG_AUDIO_PLAYBACK 0 314 | //const double gf0 = 18100 * M_PI * 2; 315 | //const double gf1 = 18300 * M_PI * 2; 316 | //const double gf2 = 18900 * M_PI * 2; 317 | //const double gf3 = 19700 * M_PI * 2; 318 | 319 | u_int32_t r0 = 0; 320 | u_int32_t r1 = 0; 321 | 322 | double audioFunction(double t, float *frequenciesToSend) 323 | { 324 | #if DEBUG_AUDIO_PLAYBACK == 1 325 | return sin(t * 587.33); 326 | #endif 327 | 328 | if(frequenciesToSend == NULL) return 0; 329 | 330 | double sum = 0.0; 331 | double divisor = 0; 332 | for (int i = 0; i < kNumberOfTransmitFrequencies; i++) 333 | { 334 | double freq = frequenciesToSend[i]; 335 | sum += sin(t * freq) * amplitudeAdjustments[i]; 336 | divisor += freq > 1 ? 1 : 0; 337 | } 338 | 339 | 340 | /*if(r0 < UINT32_MAX / 4) 341 | { 342 | sum += sin(t * gf0); 343 | } 344 | else if(r0 >= UINT32_MAX / 4 && r0 < UINT32_MAX / 2) 345 | { 346 | sum += sin(t * gf1); 347 | } 348 | else if(r0 > UINT32_MAX / 2 && r0 < (u_int32_t)(UINT32_MAX * 0.75)) 349 | { 350 | sum += sin(t * gf2); 351 | } 352 | else 353 | { 354 | sum += sin(t * gf3); 355 | } 356 | divisor++; 357 | 358 | 359 | 360 | if(r1 < UINT32_MAX / 4) 361 | { 362 | sum += sin(t * gf2); 363 | } 364 | else if(r1 >= UINT32_MAX / 4 && r1 < UINT32_MAX / 2) 365 | { 366 | sum += sin(t * gf0); 367 | } 368 | else if(r1 > UINT32_MAX / 2 && r1 < (u_int32_t)(UINT32_MAX * 0.75)) 369 | { 370 | sum += sin(t * gf3); 371 | } 372 | else 373 | { 374 | sum += sin(t * gf1); 375 | } 376 | divisor++;*/ 377 | 378 | /*sum += sin(t * gf1); 379 | divisor++;*/ 380 | 381 | if(divisor == 0) 382 | { 383 | return 0; 384 | } 385 | 386 | 387 | return sum / divisor; 388 | } 389 | 390 | 391 | float amplitudeAdjustmentsIPadTransmit[] = {4.0, 4.0, 10.0, 20.0, 1.0, 1.0, 1.0, 1.0}; // Arbitrary numbers to boost certain frequencies by (experimentally determined) 392 | float amplitudeAdjustmentsITouchTransmit[] = {4.0, 5.0, 4.0, 1.0, 1.0, 1.0, 1.0, 1.0}; // Arbitrary numbers to boost certain frequencies by (experimentally determined) 393 | //float amplitudeAdjustmentsITouchTransmit[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; // Arbitrary numbers to boost certain frequencies by (experimentally determined) 394 | float *amplitudeAdjustments; // Set at runtime for specific device; 395 | 396 | int currentFrame = 0; 397 | double maxCallCount = 14592.0 * (kTransmitInterval / 0.4); 398 | 399 | double rampUp = 0.2; 400 | double rampDown = 0.8; 401 | 402 | - (void) renderAudioIntoData:(Float32 *)data withSampleRate:(double)sampleRate numberOfFrames:(int)numberOfFrames 403 | { 404 | if(self.isPlaying) 405 | { 406 | for (UInt32 frame = 0; frame < numberOfFrames; frame++) 407 | { 408 | if(frequenciesToSend == NULL || self.frequenciesChanging) 409 | { 410 | data[frame] = 0; 411 | continue; 412 | } 413 | 414 | self.t += 1.0 / sampleRate; 415 | double time = self.t * 2 * M_PI; 416 | 417 | if(self.isTransmittingDelimiter) 418 | { 419 | data[frame] = sin(time * kPacketDelimiterFrequency) * 5; 420 | continue; 421 | } 422 | 423 | 424 | double progress = (double) (currentFrame / (double) maxCallCount); 425 | double ramp = 0.0; 426 | if (progress <= rampUp) 427 | { 428 | ramp = progress / rampUp; 429 | } 430 | else if(progress > rampUp && progress <= rampDown) 431 | { 432 | ramp = 1.0; 433 | } 434 | else 435 | { 436 | ramp = 1.0 - (progress - rampDown) / (1.0 - rampDown); 437 | } 438 | ramp = MIN(ramp, 1.0); 439 | 440 | 441 | ramp = MAX(ramp, 0.0); 442 | 443 | data[frame] = audioFunction(time, frequenciesToSend) * ramp; 444 | currentFrame++; 445 | } 446 | } 447 | } 448 | 449 | - (void) fftData:(float *)data arraySize:(int)size cutoff:(float)cutoff 450 | { 451 | [self.receiveDelegate audioReceivedFFTData:data arraySize:size cutoff:cutoff]; 452 | } 453 | 454 | - (NSArray *) convertByteToBoolData:(Byte) byte 455 | { 456 | /*NSMutableArray *tempBools = [NSMutableArray array]; 457 | for(int i = 0; i < 8; i++) 458 | { 459 | BOOL b = (num & (uint)pow(2, i)) != 0 ? YES : NO; 460 | [tempBools addObject:@(b)]; 461 | } 462 | 463 | return [tempBools copy];*/ 464 | 465 | 466 | BOOL p0 = (byte & 0x01) != 0 ? YES : NO; 467 | BOOL p1 = (byte & 0x02) != 0 ? YES : NO; 468 | BOOL p2 = (byte & 0x04) != 0 ? YES : NO; 469 | BOOL p3 = (byte & 0x08) != 0 ? YES : NO; 470 | BOOL p4 = (byte & 0x10) != 0 ? YES : NO; 471 | BOOL p5 = (byte & 0x20) != 0 ? YES : NO; 472 | BOOL p6 = (byte & 0x40) != 0 ? YES : NO; 473 | BOOL p7 = (byte & 0x80) != 0 ? YES : NO; 474 | 475 | return @[@(p0), @(p1), @(p2), @(p3), @(p4), @(p5), @(p6), @(p7)]; 476 | 477 | } 478 | 479 | - (void) start 480 | { 481 | if(self.isReceiving) 482 | { 483 | [self.receivedPacketData removeAllObjects]; 484 | self.FFTTimer = [NSTimer timerWithTimeInterval:kFFTInterval target:self selector:@selector(getTransmittedData) userInfo:nil repeats:YES]; 485 | [[NSRunLoop mainRunLoop] addTimer:self.FFTTimer forMode:NSRunLoopCommonModes]; 486 | } 487 | else 488 | { 489 | self.isPlaying = YES; 490 | } 491 | self.audio.isReceiving = self.isReceiving; 492 | 493 | [self.audio startAudio]; 494 | } 495 | 496 | - (void) stop 497 | { 498 | [self.FFTTimer invalidate]; 499 | self.isPlaying = NO; 500 | 501 | [self.audio stopAudio]; 502 | } 503 | 504 | - (void) setIsReceiving:(BOOL)isReceiving 505 | { 506 | _isReceiving = isReceiving; 507 | self.audio.isReceiving = isReceiving; 508 | } 509 | @end 510 | -------------------------------------------------------------------------------- /Ultrasound/CADebugMacros.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: CADebugMacros.cpp 4 | Abstract: Helper class for printing debug messages 5 | Version: 1.21 6 | 7 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 8 | Inc. ("Apple") in consideration of your agreement to the following 9 | terms, and your use, installation, modification or redistribution of 10 | this Apple software constitutes acceptance of these terms. If you do 11 | not agree with these terms, please do not use, install, modify or 12 | redistribute this Apple software. 13 | 14 | In consideration of your agreement to abide by the following terms, and 15 | subject to these terms, Apple grants you a personal, non-exclusive 16 | license, under Apple's copyrights in this original Apple software (the 17 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 18 | Software, with or without modifications, in source and/or binary forms; 19 | provided that if you redistribute the Apple Software in its entirety and 20 | without modifications, you must retain this notice and the following 21 | text and disclaimers in all such redistributions of the Apple Software. 22 | Neither the name, trademarks, service marks or logos of Apple Inc. may 23 | be used to endorse or promote products derived from the Apple Software 24 | without specific prior written permission from Apple. Except as 25 | expressly stated in this notice, no other rights or licenses, express or 26 | implied, are granted by Apple herein, including but not limited to any 27 | patent rights that may be infringed by your derivative works or by other 28 | works in which the Apple Software may be incorporated. 29 | 30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 31 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 32 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 33 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 34 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 35 | 36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 37 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 40 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 41 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 42 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 43 | POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2010 Apple Inc. All Rights Reserved. 46 | 47 | 48 | */ 49 | 50 | #include "CADebugMacros.h" 51 | #include 52 | #include 53 | #if TARGET_API_MAC_OSX 54 | #include 55 | #endif 56 | 57 | #if DEBUG 58 | #include 59 | 60 | void DebugPrint(const char *fmt, ...) 61 | { 62 | va_list args; 63 | va_start(args, fmt); 64 | vprintf(fmt, args); 65 | va_end(args); 66 | } 67 | #endif // DEBUG 68 | 69 | #if TARGET_API_MAC_OSX 70 | void LogError(const char *fmt, ...) 71 | { 72 | va_list args; 73 | va_start(args, fmt); 74 | #if DEBUG 75 | vprintf(fmt, args); 76 | #endif 77 | vsyslog(LOG_ERR, fmt, args); 78 | va_end(args); 79 | } 80 | 81 | void LogWarning(const char *fmt, ...) 82 | { 83 | va_list args; 84 | va_start(args, fmt); 85 | #if DEBUG 86 | vprintf(fmt, args); 87 | #endif 88 | vsyslog(LOG_WARNING, fmt, args); 89 | va_end(args); 90 | } 91 | #endif 92 | -------------------------------------------------------------------------------- /Ultrasound/CAMath.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: CAMath.h 4 | Abstract: Helper class for various math functions 5 | Version: 1.21 6 | 7 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 8 | Inc. ("Apple") in consideration of your agreement to the following 9 | terms, and your use, installation, modification or redistribution of 10 | this Apple software constitutes acceptance of these terms. If you do 11 | not agree with these terms, please do not use, install, modify or 12 | redistribute this Apple software. 13 | 14 | In consideration of your agreement to abide by the following terms, and 15 | subject to these terms, Apple grants you a personal, non-exclusive 16 | license, under Apple's copyrights in this original Apple software (the 17 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 18 | Software, with or without modifications, in source and/or binary forms; 19 | provided that if you redistribute the Apple Software in its entirety and 20 | without modifications, you must retain this notice and the following 21 | text and disclaimers in all such redistributions of the Apple Software. 22 | Neither the name, trademarks, service marks or logos of Apple Inc. may 23 | be used to endorse or promote products derived from the Apple Software 24 | without specific prior written permission from Apple. Except as 25 | expressly stated in this notice, no other rights or licenses, express or 26 | implied, are granted by Apple herein, including but not limited to any 27 | patent rights that may be infringed by your derivative works or by other 28 | works in which the Apple Software may be incorporated. 29 | 30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 31 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 32 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 33 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 34 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 35 | 36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 37 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 40 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 41 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 42 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 43 | POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2010 Apple Inc. All Rights Reserved. 46 | 47 | 48 | */ 49 | 50 | #ifndef __CAMath_h__ 51 | #define __CAMath_h__ 52 | 53 | #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 54 | #include 55 | #else 56 | #include 57 | #endif 58 | 59 | inline bool fiszero(Float64 f) { return (f == 0.); } 60 | inline bool fiszero(Float32 f) { return (f == 0.f); } 61 | 62 | inline bool fnonzero(Float64 f) { return !fiszero(f); } 63 | inline bool fnonzero(Float32 f) { return !fiszero(f); } 64 | 65 | inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; } 66 | inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; } 67 | 68 | inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); } 69 | inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); } 70 | 71 | #endif // __CAMath_h__ 72 | -------------------------------------------------------------------------------- /Ultrasound/CAStreamBasicDescription.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: CAStreamBasicDescription.h 4 | Abstract: Helper class for audio stream descriptions 5 | Version: 1.21 6 | 7 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 8 | Inc. ("Apple") in consideration of your agreement to the following 9 | terms, and your use, installation, modification or redistribution of 10 | this Apple software constitutes acceptance of these terms. If you do 11 | not agree with these terms, please do not use, install, modify or 12 | redistribute this Apple software. 13 | 14 | In consideration of your agreement to abide by the following terms, and 15 | subject to these terms, Apple grants you a personal, non-exclusive 16 | license, under Apple's copyrights in this original Apple software (the 17 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 18 | Software, with or without modifications, in source and/or binary forms; 19 | provided that if you redistribute the Apple Software in its entirety and 20 | without modifications, you must retain this notice and the following 21 | text and disclaimers in all such redistributions of the Apple Software. 22 | Neither the name, trademarks, service marks or logos of Apple Inc. may 23 | be used to endorse or promote products derived from the Apple Software 24 | without specific prior written permission from Apple. Except as 25 | expressly stated in this notice, no other rights or licenses, express or 26 | implied, are granted by Apple herein, including but not limited to any 27 | patent rights that may be infringed by your derivative works or by other 28 | works in which the Apple Software may be incorporated. 29 | 30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 31 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 32 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 33 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 34 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 35 | 36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 37 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 40 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 41 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 42 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 43 | POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2010 Apple Inc. All Rights Reserved. 46 | 47 | 48 | */ 49 | 50 | 51 | #ifndef __CAStreamBasicDescription_h__ 52 | #define __CAStreamBasicDescription_h__ 53 | 54 | #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 55 | #include 56 | #include 57 | #else 58 | #include "CoreAudioTypes.h" 59 | #include "CoreFoundation.h" 60 | #endif 61 | 62 | #include "CADebugMacros.h" 63 | #include // for memset, memcpy 64 | #include // for FILE * 65 | 66 | #pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it 67 | 68 | // define Leopard specific symbols for backward compatibility if applicable 69 | #if COREAUDIOTYPES_VERSION < 1050 70 | typedef Float32 AudioSampleType; 71 | enum { kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked }; 72 | #endif 73 | #if COREAUDIOTYPES_VERSION < 1051 74 | typedef Float32 AudioUnitSampleType; 75 | #endif 76 | 77 | // define the IsMixable format flag for all versions of the system 78 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) 79 | enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable }; 80 | #else 81 | enum { kIsNonMixableFlag = (1L << 6) }; 82 | #endif 83 | 84 | //============================================================================= 85 | // CAStreamBasicDescription 86 | // 87 | // This is a wrapper class for the AudioStreamBasicDescription struct. 88 | // It adds a number of convenience routines, but otherwise adds nothing 89 | // to the footprint of the original struct. 90 | //============================================================================= 91 | class CAStreamBasicDescription : 92 | public AudioStreamBasicDescription 93 | { 94 | 95 | // Constants 96 | public: 97 | static const AudioStreamBasicDescription sEmpty; 98 | 99 | // Construction/Destruction 100 | public: 101 | CAStreamBasicDescription() { memset (this, 0, sizeof(AudioStreamBasicDescription)); } 102 | 103 | CAStreamBasicDescription(const AudioStreamBasicDescription &desc) 104 | { 105 | SetFrom(desc); 106 | } 107 | 108 | CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID, 109 | UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, 110 | UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, 111 | UInt32 inBitsPerChannel, UInt32 inFormatFlags); 112 | 113 | // Assignment 114 | CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; } 115 | 116 | void SetFrom(const AudioStreamBasicDescription &desc) 117 | { 118 | memcpy(this, &desc, sizeof(AudioStreamBasicDescription)); 119 | } 120 | 121 | // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 122 | // 123 | // interrogation 124 | 125 | bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; } 126 | 127 | bool PackednessIsSignificant() const 128 | { 129 | //Assert(IsPCM(), "PackednessIsSignificant only applies for PCM"); 130 | return (SampleWordSize() << 3) != mBitsPerChannel; 131 | } 132 | 133 | bool AlignmentIsSignificant() const 134 | { 135 | return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0; 136 | } 137 | 138 | bool IsInterleaved() const 139 | { 140 | return !IsPCM() || !(mFormatFlags & kAudioFormatFlagIsNonInterleaved); 141 | } 142 | 143 | // for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these: 144 | UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; } 145 | UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; } 146 | UInt32 NumberChannels() const { return mChannelsPerFrame; } 147 | UInt32 SampleWordSize() const { 148 | return (mBytesPerFrame > 0 && NumberInterleavedChannels()) ? mBytesPerFrame / NumberInterleavedChannels() : 0; 149 | } 150 | 151 | UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; } 152 | UInt32 BytesToFrames(UInt32 nbytes) const { 153 | //Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames"); 154 | return nbytes / mBytesPerFrame; 155 | } 156 | 157 | bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const 158 | { 159 | return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved(); 160 | } 161 | 162 | // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 163 | // 164 | // manipulation 165 | 166 | void SetCanonical(UInt32 nChannels, bool interleaved) 167 | // note: leaves sample rate untouched 168 | { 169 | mFormatID = kAudioFormatLinearPCM; 170 | #if TARGET_IPHONE_SIMULATOR 171 | int sampleSize = sizeof(Float32); 172 | mFormatFlags = kAudioFormatFlagsNativeFloatPacked; 173 | #else 174 | int sampleSize = sizeof(AudioSampleType); 175 | mFormatFlags = kAudioFormatFlagsCanonical; 176 | #endif 177 | mBitsPerChannel = 8 * sampleSize; 178 | mChannelsPerFrame = nChannels; 179 | mFramesPerPacket = 1; 180 | if (interleaved) 181 | mBytesPerPacket = mBytesPerFrame = nChannels * sampleSize; 182 | else { 183 | mBytesPerPacket = mBytesPerFrame = sampleSize; 184 | mFormatFlags |= kAudioFormatFlagIsNonInterleaved; 185 | } 186 | } 187 | 188 | bool IsCanonical() const 189 | { 190 | if (mFormatID != kAudioFormatLinearPCM) return false; 191 | UInt32 reqFormatFlags; 192 | #if (COREAUDIOTYPES_VERSION <= 1050) 193 | UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsAlignedHigh); 194 | #else 195 | UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagsSampleFractionMask); 196 | #endif 197 | bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; 198 | #if TARGET_IPHONE_SIMULATOR 199 | unsigned sampleSize = sizeof(Float32); 200 | reqFormatFlags = kAudioFormatFlagsNativeFloatPacked; 201 | #else 202 | unsigned sampleSize = sizeof(AudioSampleType); 203 | reqFormatFlags = kAudioFormatFlagsCanonical; 204 | #endif 205 | UInt32 reqFrameSize = interleaved ? (mChannelsPerFrame * sampleSize) : sampleSize; 206 | 207 | return ((mFormatFlags & flagsMask) == reqFormatFlags 208 | && mBitsPerChannel == 8 * sampleSize 209 | && mFramesPerPacket == 1 210 | && mBytesPerFrame == reqFrameSize 211 | && mBytesPerPacket == reqFrameSize); 212 | } 213 | 214 | void SetAUCanonical(UInt32 nChannels, bool interleaved) 215 | { 216 | mFormatID = kAudioFormatLinearPCM; 217 | #if CA_PREFER_FIXED_POINT 218 | mFormatFlags = kAudioFormatFlagsCanonical | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift); 219 | #else 220 | mFormatFlags = kAudioFormatFlagsCanonical; 221 | #endif 222 | mChannelsPerFrame = nChannels; 223 | mFramesPerPacket = 1; 224 | mBitsPerChannel = 8 * sizeof(AudioUnitSampleType); 225 | if (interleaved) 226 | mBytesPerPacket = mBytesPerFrame = nChannels * sizeof(AudioUnitSampleType); 227 | else { 228 | mBytesPerPacket = mBytesPerFrame = sizeof(AudioUnitSampleType); 229 | mFormatFlags |= kAudioFormatFlagIsNonInterleaved; 230 | } 231 | } 232 | 233 | void ChangeNumberChannels(UInt32 nChannels, bool interleaved) 234 | // alter an existing format 235 | { 236 | //Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats"); 237 | UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING 238 | if (wordSize == 0) 239 | wordSize = (mBitsPerChannel + 7) / 8; 240 | mChannelsPerFrame = nChannels; 241 | mFramesPerPacket = 1; 242 | if (interleaved) { 243 | mBytesPerPacket = mBytesPerFrame = nChannels * wordSize; 244 | mFormatFlags &= ~kAudioFormatFlagIsNonInterleaved; 245 | } else { 246 | mBytesPerPacket = mBytesPerFrame = wordSize; 247 | mFormatFlags |= kAudioFormatFlagIsNonInterleaved; 248 | } 249 | } 250 | 251 | // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 252 | // 253 | // other 254 | 255 | bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards=true) const; 256 | 257 | void Print() const { 258 | Print (stdout); 259 | } 260 | 261 | void Print(FILE* file) const { 262 | PrintFormat (file, "", "AudioStreamBasicDescription:"); 263 | } 264 | 265 | void PrintFormat(FILE *f, const char *indent, const char *name) const { 266 | char buf[256]; 267 | fprintf(f, "%s%s %s\n", indent, name, AsString(buf, sizeof(buf))); 268 | } 269 | 270 | void PrintFormat2(FILE *f, const char *indent, const char *name) const { // no trailing newline 271 | char buf[256]; 272 | fprintf(f, "%s%s %s", indent, name, AsString(buf, sizeof(buf))); 273 | } 274 | 275 | char * AsString(char *buf, size_t bufsize) const; 276 | 277 | static void Print (const AudioStreamBasicDescription &inDesc) 278 | { 279 | CAStreamBasicDescription desc(inDesc); 280 | desc.Print (); 281 | } 282 | 283 | OSStatus Save(CFPropertyListRef *outData) const; 284 | 285 | OSStatus Restore(CFPropertyListRef &inData); 286 | 287 | // Operations 288 | static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); } 289 | static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription); 290 | static void ResetFormat(AudioStreamBasicDescription& ioDescription); 291 | static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription); 292 | static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate); 293 | #if CoreAudio_Debug 294 | static void PrintToLog(const AudioStreamBasicDescription& inDesc); 295 | #endif 296 | }; 297 | 298 | bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); 299 | bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); 300 | #if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600)) 301 | inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); } 302 | inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); } 303 | inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); } 304 | inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); } 305 | #endif 306 | 307 | bool SanityCheck(const AudioStreamBasicDescription& x); 308 | 309 | 310 | #endif // __CAStreamBasicDescription_h__ 311 | -------------------------------------------------------------------------------- /Ultrasound/CAXException.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: CAXException.cpp 4 | Abstract: Helper class for excpetion handling 5 | Version: 1.21 6 | 7 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 8 | Inc. ("Apple") in consideration of your agreement to the following 9 | terms, and your use, installation, modification or redistribution of 10 | this Apple software constitutes acceptance of these terms. If you do 11 | not agree with these terms, please do not use, install, modify or 12 | redistribute this Apple software. 13 | 14 | In consideration of your agreement to abide by the following terms, and 15 | subject to these terms, Apple grants you a personal, non-exclusive 16 | license, under Apple's copyrights in this original Apple software (the 17 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 18 | Software, with or without modifications, in source and/or binary forms; 19 | provided that if you redistribute the Apple Software in its entirety and 20 | without modifications, you must retain this notice and the following 21 | text and disclaimers in all such redistributions of the Apple Software. 22 | Neither the name, trademarks, service marks or logos of Apple Inc. may 23 | be used to endorse or promote products derived from the Apple Software 24 | without specific prior written permission from Apple. Except as 25 | expressly stated in this notice, no other rights or licenses, express or 26 | implied, are granted by Apple herein, including but not limited to any 27 | patent rights that may be infringed by your derivative works or by other 28 | works in which the Apple Software may be incorporated. 29 | 30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 31 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 32 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 33 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 34 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 35 | 36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 37 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 40 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 41 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 42 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 43 | POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2010 Apple Inc. All Rights Reserved. 46 | 47 | 48 | */ 49 | 50 | 51 | #include "CAXException.h" 52 | 53 | CAXException::WarningHandler CAXException::sWarningHandler = NULL; 54 | -------------------------------------------------------------------------------- /Ultrasound/CAXException.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: CAXException.h 4 | Abstract: Helper class for excpetion handling 5 | Version: 1.21 6 | 7 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 8 | Inc. ("Apple") in consideration of your agreement to the following 9 | terms, and your use, installation, modification or redistribution of 10 | this Apple software constitutes acceptance of these terms. If you do 11 | not agree with these terms, please do not use, install, modify or 12 | redistribute this Apple software. 13 | 14 | In consideration of your agreement to abide by the following terms, and 15 | subject to these terms, Apple grants you a personal, non-exclusive 16 | license, under Apple's copyrights in this original Apple software (the 17 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 18 | Software, with or without modifications, in source and/or binary forms; 19 | provided that if you redistribute the Apple Software in its entirety and 20 | without modifications, you must retain this notice and the following 21 | text and disclaimers in all such redistributions of the Apple Software. 22 | Neither the name, trademarks, service marks or logos of Apple Inc. may 23 | be used to endorse or promote products derived from the Apple Software 24 | without specific prior written permission from Apple. Except as 25 | expressly stated in this notice, no other rights or licenses, express or 26 | implied, are granted by Apple herein, including but not limited to any 27 | patent rights that may be infringed by your derivative works or by other 28 | works in which the Apple Software may be incorporated. 29 | 30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 31 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 32 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 33 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 34 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 35 | 36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 37 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 40 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 41 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 42 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 43 | POSSIBILITY OF SUCH DAMAGE. 44 | 45 | Copyright (C) 2010 Apple Inc. All Rights Reserved. 46 | 47 | 48 | */ 49 | 50 | 51 | #ifndef __CAXException_h__ 52 | #define __CAXException_h__ 53 | 54 | #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 55 | #include 56 | #else 57 | #include 58 | #include 59 | #endif 60 | #include "CADebugMacros.h" 61 | #include 62 | #include 63 | #include 64 | 65 | class CAX4CCString { 66 | public: 67 | CAX4CCString(OSStatus error) { 68 | // see if it appears to be a 4-char-code 69 | char *str = mStr; 70 | *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error); 71 | if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) { 72 | str[0] = str[5] = '\''; 73 | str[6] = '\0'; 74 | } else if (error > -200000 && error < 200000) 75 | // no, format it as an integer 76 | sprintf(str, "%d", (int)error); 77 | else 78 | sprintf(str, "0x%x", (int)error); 79 | } 80 | const char *get() const { return mStr; } 81 | operator const char *() const { return mStr; } 82 | private: 83 | char mStr[16]; 84 | }; 85 | 86 | // An extended exception class that includes the name of the failed operation 87 | class CAXException { 88 | public: 89 | CAXException(const char *operation, OSStatus err) : 90 | mError(err) 91 | { 92 | if (operation == NULL) 93 | mOperation[0] = '\0'; 94 | else if (strlen(operation) >= sizeof(mOperation)) { 95 | memcpy(mOperation, operation, sizeof(mOperation) - 1); 96 | mOperation[sizeof(mOperation) - 1] = '\0'; 97 | } else 98 | strcpy(mOperation, operation); 99 | } 100 | 101 | char *FormatError(char *str) const 102 | { 103 | return FormatError(str, mError); 104 | } 105 | 106 | char mOperation[256]; 107 | const OSStatus mError; 108 | 109 | // ------------------------------------------------- 110 | 111 | typedef void (*WarningHandler)(const char *msg, OSStatus err); 112 | 113 | static char *FormatError(char *str, OSStatus error) 114 | { 115 | strcpy(str, CAX4CCString(error)); 116 | return str; 117 | } 118 | 119 | static void Warning(const char *s, OSStatus error) 120 | { 121 | if (sWarningHandler) 122 | (*sWarningHandler)(s, error); 123 | } 124 | 125 | static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; } 126 | private: 127 | static WarningHandler sWarningHandler; 128 | }; 129 | 130 | #if DEBUG || CoreAudio_Debug 131 | #define XThrowIfError(error, operation) \ 132 | do { \ 133 | OSStatus __err = error; \ 134 | if (__err) { \ 135 | DebugMessageN2("about to throw %s: %s", CAX4CCString(error).get(), operation);\ 136 | STOP; \ 137 | throw CAXException(operation, __err); \ 138 | } \ 139 | } while (0) 140 | 141 | #define XThrowIf(condition, error, operation) \ 142 | do { \ 143 | if (condition) { \ 144 | OSStatus __err = error; \ 145 | DebugMessageN2("about to throw %s: %s", CAX4CCString(error).get(), operation);\ 146 | STOP; \ 147 | throw CAXException(operation, __err); \ 148 | } \ 149 | } while (0) 150 | 151 | #define XRequireNoError(error, label) \ 152 | do { \ 153 | OSStatus __err = error; \ 154 | if (__err) { \ 155 | DebugMessageN2("about to throw %s: %s", CAX4CCString(error).get(), #error);\ 156 | STOP; \ 157 | goto label; \ 158 | } \ 159 | } while (0) 160 | 161 | #define XAssert(assertion) \ 162 | do { \ 163 | if (!(assertion)) { \ 164 | DebugMessageN1("error: failed assertion: %s", #assertion);\ 165 | STOP; \ 166 | } \ 167 | } while (0) 168 | 169 | #define XAssertNoError(error) \ 170 | do { \ 171 | OSStatus __err = error; \ 172 | if (__err) { \ 173 | DebugMessageN2("error %s: %s", CAX4CCString(error).get(), #error);\ 174 | STOP; \ 175 | } \ 176 | } while (0) 177 | 178 | #else 179 | #define XThrowIfError(error, operation) \ 180 | do { \ 181 | OSStatus __err = error; \ 182 | if (__err) { \ 183 | throw CAXException(operation, __err); \ 184 | } \ 185 | } while (0) 186 | 187 | #define XThrowIf(condition, error, operation) \ 188 | do { \ 189 | if (condition) { \ 190 | OSStatus __err = error; \ 191 | throw CAXException(operation, __err); \ 192 | } \ 193 | } while (0) 194 | 195 | #define XRequireNoError(error, label) \ 196 | do { \ 197 | OSStatus __err = error; \ 198 | if (__err) { \ 199 | goto label; \ 200 | } \ 201 | } while (0) 202 | 203 | #define XAssert(assertion) \ 204 | do { \ 205 | } while (0) 206 | 207 | #define XAssertNoError(error) \ 208 | do { \ 209 | /*OSStatus __err =*/ error; \ 210 | } while (0) 211 | #endif 212 | 213 | #define XThrow(error, operation) XThrowIf(true, error, operation) 214 | #define XThrowIfErr(error) XThrowIfError(error, #error) 215 | 216 | #endif // __CAXException_h__ 217 | -------------------------------------------------------------------------------- /Ultrasound/CardIO/CardIO.h: -------------------------------------------------------------------------------- 1 | // 2 | // CardIO.h 3 | // Copyright (c) 2011-2013 PayPal. All rights reserved. 4 | // 5 | 6 | // All-in-one header file for card.io sdk. 7 | 8 | #import "CardIOPaymentViewController.h" 9 | #import "CardIOPaymentViewControllerDelegate.h" 10 | #import "CardIOCreditCardInfo.h" 11 | -------------------------------------------------------------------------------- /Ultrasound/CardIO/CardIOCreditCardInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // CardIOCreditCardInfo.h 3 | // Copyright (c) 2011-2013 PayPal. All rights reserved. 4 | // 5 | 6 | #import 7 | 8 | typedef enum { 9 | CardIOCreditCardTypeUnknown = 0, // deprecated; use CardIOCreditCardTypeUnrecognized or CardIOCreditCardTypeAmbiguous 10 | CardIOCreditCardTypeUnrecognized = 0, // the card number does not correspond to any recognizable card type 11 | CardIOCreditCardTypeAmbiguous = 1, // the card number corresponds to multiple card types (e.g. when only a few digits have been entered) 12 | CardIOCreditCardTypeAmex = '3', 13 | CardIOCreditCardTypeJCB = 'J', 14 | CardIOCreditCardTypeVisa = '4', 15 | CardIOCreditCardTypeMastercard = '5', 16 | CardIOCreditCardTypeDiscover = '6' 17 | } CardIOCreditCardType; 18 | 19 | 20 | @interface CardIOCreditCardInfo : NSObject 21 | 22 | @property(nonatomic, copy, readwrite) NSString *cardNumber; 23 | @property(nonatomic, copy, readonly) NSString *redactedCardNumber; // card number with all but the last four digits obfuscated 24 | 25 | // expiryMonth & expiryYear may be 0, if expiry information is not requested 26 | @property(nonatomic, assign, readwrite) NSUInteger expiryMonth; // January == 1 27 | @property(nonatomic, assign, readwrite) NSUInteger expiryYear; // the full four digit year 28 | 29 | // cvv and/or zip may be nil, if not requested 30 | @property(nonatomic, copy, readwrite) NSString *cvv; 31 | @property(nonatomic, copy, readwrite) NSString *zip; 32 | 33 | // was the card number scanned (as opposed to manually entered)? 34 | @property(nonatomic, assign, readwrite) BOOL scanned; 35 | 36 | // Derived from cardNumber. 37 | // When provided by card.io, cardType will not be CardIOCreditCardTypeUnrecognized or CardIOCreditCardTypeAmbiguous. 38 | @property(nonatomic, assign, readonly) CardIOCreditCardType cardType; 39 | 40 | // Convenience method to return a card type string (e.g. "Visa", "American Express", "JCB", "MasterCard", or "Discover") suitable for display. 41 | // Where appropriate, this string will be translated into the language specified. 42 | // (See CardIOPaymentViewController.h for a detailed explanation of languageOrLocale.) 43 | + (NSString *)displayStringForCardType:(CardIOCreditCardType)cardType usingLanguageOrLocale:(NSString *)languageOrLocale; 44 | 45 | // Returns a 36x25 credit card logo, at a resolution appropriate for the device 46 | + (UIImage *)logoForCardType:(CardIOCreditCardType)cardType; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Ultrasound/CardIO/CardIOPaymentViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CardIOPaymentViewController.h 3 | // Copyright (c) 2011-2013 PayPal. All rights reserved. 4 | // 5 | 6 | #import 7 | #import "CardIOPaymentViewControllerDelegate.h" 8 | 9 | // CardIOPaymentViewController is the main entry point into the card.io SDK. 10 | @interface CardIOPaymentViewController : UINavigationController 11 | 12 | // Initializer for scanning only. 13 | - (id)initWithPaymentDelegate:(id)aDelegate; 14 | 15 | // Initializer for scanning only, with extra hooks for controlling whether the camera will be displayed (useful for testing). 16 | // If scanningEnabled is NO, card.io will use manual entry, regardless of whether scanning is supported. (Default value is YES.) 17 | - (id)initWithPaymentDelegate:(id)aDelegate scanningEnabled:(BOOL)scanningEnabled; 18 | 19 | // Set your app token. If not set before presenting the view controller, an exception will be thrown. 20 | @property(nonatomic, copy, readwrite) NSString *appToken; 21 | 22 | // The preferred language for all strings appearing in the user interface. 23 | // If not set, or if set to nil, defaults to the device's current language setting. 24 | // 25 | // Can be specified as a language code ("en", "fr", "zh-Hans", etc.) or as a locale ("en_AU", "fr_FR", "zh-Hant_HK", etc.). 26 | // If card.io does not contain localized strings for a specified locale, then will fall back to the language. E.g., "es_CO" -> "es". 27 | // If card.io does not contain localized strings for a specified region, then will fall back to American English. 28 | // 29 | // If you specify only a language code, and that code matches the device's currently preferred language, 30 | // then card.io will attempt to use the device's current region as well. 31 | // E.g., specifying "en" on a device set to "English" and "United Kingdom" will result in "en_GB". 32 | // 33 | // These localizations are currently included: da,de,en,en_AU,en_GB,en_SV,en_U5,es,fr,he,it,ja,nb,nl,pl,pt,ru,sv,tr,zh-Hans,zh-Hant_HK,zh-Hant_TW. 34 | @property(nonatomic, copy, readwrite) NSString *languageOrLocale; 35 | 36 | // If YES, the status bar's style will be kept as whatever your app has set it to. 37 | // If NO, the status bar style will be set to UIStatusBarStyleBlackOpaque. 38 | // Defaults to NO. 39 | @property(nonatomic, assign, readwrite) BOOL keepStatusBarStyle; 40 | 41 | // The default appearance of the navigation bar is UIBarStyleDefault, tintColor == nil. 42 | // Set either or both of these properties if you want to override these defaults. 43 | @property(nonatomic, assign, readwrite) UIBarStyle navigationBarStyle; 44 | @property(nonatomic, retain, readwrite) UIColor *navigationBarTintColor; 45 | 46 | // Normally, card.io blurs the screen when the app is backgrounded, 47 | // to obscure card details in the iOS-saved screenshot. 48 | // If your app already does its own blurring upon backgrounding, you might choose to disable this. 49 | // Defaults to NO. 50 | @property(nonatomic, assign, readwrite) BOOL disableBlurWhenBackgrounding; 51 | 52 | // Set to NO if you don't need to collect the card expiration. Defaults to YES. 53 | @property(nonatomic, assign, readwrite) BOOL collectExpiry; 54 | 55 | // Set to NO if you don't need to collect the CVV from the user. Defaults to YES. 56 | @property(nonatomic, assign, readwrite) BOOL collectCVV; 57 | 58 | // Set to YES if you need to collect the billing zip code. Defaults to NO. 59 | @property(nonatomic, assign, readwrite) BOOL collectZip; 60 | 61 | // Set to NO if you want to suppress the first-time how-to alert view. Defaults to YES. 62 | @property(nonatomic, assign, readwrite) BOOL showsFirstUseAlert; 63 | 64 | // Set to YES to show the card.io logo over the camera instead of the PayPal logo. Defaults to NO. 65 | @property(nonatomic, assign, readwrite) BOOL useCardIOLogo; 66 | 67 | // Set to YES to prevent card.io from showing manual entry buttons internally. Defaults to NO. 68 | // If you want to prevent users from *ever* seeing card.io's manual entry screen, you should also: 69 | // * Check +canReadCardWithCamera before initing the view controller. If +canReadCardWithCamera 70 | // returns false, card.io will display a manual entry screen if presented. 71 | // * If needed for UI updates such as disabling/removing card scan buttons, subscribe to scan 72 | // notifications; see +(start|stop)GeneratingScanAvailabilityNotifications. 73 | @property(nonatomic, assign, readwrite) BOOL disableManualEntryButtons; 74 | 75 | // Access to the delegate. 76 | @property(nonatomic, weak, readwrite) id paymentDelegate; 77 | 78 | // Indicates whether this device supports camera-based card scanning, including 79 | // factors like hardware support and OS version. card.io automatically provides 80 | // manual entry of cards as a fallback, so it is not necessary to check this. 81 | + (BOOL)canReadCardWithCamera; 82 | 83 | // Please send the output of this method with any technical support requests. 84 | + (NSString *)libraryVersion; 85 | @end -------------------------------------------------------------------------------- /Ultrasound/CardIO/CardIOPaymentViewControllerDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CardIOPaymentViewControllerDelegate.h 3 | // Copyright (c) 2011-2013 PayPal. All rights reserved. 4 | // 5 | 6 | #import 7 | 8 | @class CardIOPaymentViewController; 9 | @class CardIOCreditCardInfo; 10 | 11 | @protocol CardIOPaymentViewControllerDelegate 12 | 13 | @required 14 | 15 | // 16 | // Precisely one of userDidCancelPaymentViewController: or userDidProvideCreditCardInfo:inPaymentViewController: will be called. 17 | // In either case, it is your responsibility to dismiss the CardIOPaymentViewController. 18 | // 19 | 20 | // This method will be called if the user cancels the scan. You must dismiss paymentViewController. 21 | - (void)userDidCancelPaymentViewController:(CardIOPaymentViewController *)paymentViewController; 22 | 23 | // This method will be called when there is a successful scan (or manual entry). You must dismiss paymentViewController. 24 | - (void)userDidProvideCreditCardInfo:(CardIOCreditCardInfo *)info inPaymentViewController:(CardIOPaymentViewController *)paymentViewController; 25 | 26 | @end -------------------------------------------------------------------------------- /Ultrasound/CardIO/libCardIO.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisappdev/libultrasound-ios/f0d669354a984d9b769cf6818dadb6e6eaaaba56/Ultrasound/CardIO/libCardIO.a -------------------------------------------------------------------------------- /Ultrasound/Clump.h: -------------------------------------------------------------------------------- 1 | // 2 | // Clump.h 3 | // ProcessAlgo 4 | // 5 | // Created by AppDev on 7/5/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Clump : NSObject 12 | 13 | @property (nonatomic, readonly) double average; 14 | @property (nonatomic, readonly) int smallest; 15 | @property (nonatomic, readonly) int biggest; 16 | 17 | - (void) addNumber:(int) dataToAdd; 18 | @end 19 | -------------------------------------------------------------------------------- /Ultrasound/Clump.m: -------------------------------------------------------------------------------- 1 | // 2 | // Clump.m 3 | // ProcessAlgo 4 | // 5 | // Created by AppDev on 7/5/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "Clump.h" 10 | 11 | @interface Clump() 12 | @property (nonatomic) NSMutableArray *data; 13 | @end 14 | 15 | @implementation Clump 16 | 17 | - (NSMutableArray *) data 18 | { 19 | if (!_data) 20 | { 21 | _data = [NSMutableArray array]; 22 | } 23 | 24 | return _data; 25 | } 26 | 27 | - (double) average 28 | { 29 | double sum = 0.0; 30 | for (int i = 0; i < self.data.count; i++) 31 | { 32 | sum += [self.data[i] intValue]; 33 | } 34 | return sum / self.data.count; 35 | } 36 | 37 | - (int) smallest 38 | { 39 | int min = INT_MAX; 40 | for (int i = 0; i < self.data.count; i++) 41 | { 42 | min = MIN([self.data[i] intValue], min); 43 | } 44 | return min; 45 | } 46 | 47 | - (int) biggest 48 | { 49 | int max = 0; 50 | for (int i = 0; i < self.data.count; i++) 51 | { 52 | max = MAX([self.data[i] intValue], max); 53 | } 54 | return max; 55 | } 56 | 57 | - (void) addNumber:(int) dataToAdd 58 | { 59 | [self.data addObject:@(dataToAdd)]; 60 | } 61 | 62 | - (NSString *) description 63 | { 64 | return [NSString stringWithFormat:@"Clump Data: %@, avg = %f", self.data, self.average]; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Ultrasound/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisappdev/libultrasound-ios/f0d669354a984d9b769cf6818dadb6e6eaaaba56/Ultrasound/Default-568h@2x.png -------------------------------------------------------------------------------- /Ultrasound/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisappdev/libultrasound-ios/f0d669354a984d9b769cf6818dadb6e6eaaaba56/Ultrasound/Default.png -------------------------------------------------------------------------------- /Ultrasound/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisappdev/libultrasound-ios/f0d669354a984d9b769cf6818dadb6e6eaaaba56/Ultrasound/Default@2x.png -------------------------------------------------------------------------------- /Ultrasound/FFTAccelerate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FFTAccelerate.cpp 3 | 4 | 5 | Copyright (C) 2012 Tom Hoddes 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | * 13 | */ 14 | 15 | #include "FFTAccelerate.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void FFTAccelerate::doFFTReal(float samples[], float amp[], int numSamples) 23 | { 24 | int i; 25 | vDSP_Length log2n = log2f(numSamples); 26 | 27 | //Convert float array of reals samples to COMPLEX_SPLIT array A 28 | vDSP_ctoz((COMPLEX*)samples,2,&A,1,numSamples/2); 29 | 30 | //Perform FFT using fftSetup and A 31 | //Results are returned in A 32 | vDSP_fft_zrip(fftSetup, &A, 1, log2n, FFT_FORWARD); 33 | 34 | //Convert COMPLEX_SPLIT A result to float array to be returned 35 | amp[0] = A.realp[0]/(numSamples*2); 36 | for(i=1;i 18 | #include 19 | class FFTAccelerate 20 | { 21 | 22 | public: 23 | FFTAccelerate(int numSamples); 24 | ~FFTAccelerate(); 25 | void doFFTReal(float samples[], float amp[], int numSamples); 26 | 27 | private: 28 | FFTSetup fftSetup; 29 | COMPLEX_SPLIT A; 30 | } ; -------------------------------------------------------------------------------- /Ultrasound/FFTBufferManager.cpp: -------------------------------------------------------------------------------- 1 | #include "FFTBufferManager.h" 2 | 3 | #define min(x,y) (x < y) ? x : y 4 | 5 | FFTBufferManager::FFTBufferManager(UInt32 inNumberFrames) : 6 | mNeedsAudioData(0), 7 | mHasAudioData(0), 8 | mNumberFrames(inNumberFrames), 9 | mAudioBufferSize(inNumberFrames * sizeof(int32_t)), 10 | mAudioBufferCurrentIndex(0) 11 | 12 | { 13 | mAudioBuffer = (int32_t*)malloc(mAudioBufferSize); 14 | mSpectrumAnalysis = SpectrumAnalysisCreate(mNumberFrames); 15 | OSAtomicIncrement32Barrier(&mNeedsAudioData); 16 | } 17 | 18 | FFTBufferManager::~FFTBufferManager() 19 | { 20 | free(mAudioBuffer); 21 | SpectrumAnalysisDestroy(mSpectrumAnalysis); 22 | } 23 | 24 | void FFTBufferManager::GrabAudioData(AudioBufferList *inBL) 25 | { 26 | if (mAudioBufferSize < inBL->mBuffers[0].mDataByteSize) return; 27 | 28 | UInt32 bytesToCopy = min(inBL->mBuffers[0].mDataByteSize, mAudioBufferSize - mAudioBufferCurrentIndex); 29 | memcpy(mAudioBuffer+mAudioBufferCurrentIndex, inBL->mBuffers[0].mData, bytesToCopy); 30 | 31 | 32 | /*printf("Microphone Values:\n"); 33 | for(int i = 0; i < inBL->mBuffers[0].mDataByteSize * sizeof(int32_t); i += sizeof(int32_t)) 34 | { 35 | printf("%f\n", ((float *)inBL->mBuffers[0].mData)[i]); 36 | } 37 | printf("\n\n");*/ 38 | 39 | 40 | mAudioBufferCurrentIndex += bytesToCopy / sizeof(int32_t); 41 | if (mAudioBufferCurrentIndex >= mAudioBufferSize / sizeof(int32_t)) 42 | { 43 | OSAtomicIncrement32Barrier(&mHasAudioData); 44 | OSAtomicDecrement32Barrier(&mNeedsAudioData); 45 | } 46 | } 47 | 48 | Boolean FFTBufferManager::ComputeFFT(int32_t *outFFTData) 49 | { 50 | if (HasNewAudioData()) 51 | { 52 | SpectrumAnalysisProcess(mSpectrumAnalysis, mAudioBuffer, outFFTData, true); 53 | // SpectrumAnalysisProcess(mSpectrumAnalysis, mAudioBuffer, outFFTData, false); 54 | OSAtomicDecrement32Barrier(&mHasAudioData); 55 | OSAtomicIncrement32Barrier(&mNeedsAudioData); 56 | mAudioBufferCurrentIndex = 0; 57 | return true; 58 | } 59 | else if (mNeedsAudioData == 0) 60 | OSAtomicIncrement32Barrier(&mNeedsAudioData); 61 | 62 | return false; 63 | } 64 | -------------------------------------------------------------------------------- /Ultrasound/FFTBufferManager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "SpectrumAnalysis.h" 5 | 6 | class FFTBufferManager 7 | { 8 | public: 9 | FFTBufferManager(UInt32 inNumberFrames); 10 | ~FFTBufferManager(); 11 | 12 | volatile int32_t HasNewAudioData() { return mHasAudioData; } 13 | volatile int32_t NeedsNewAudioData() { return mNeedsAudioData; } 14 | 15 | UInt32 GetNumberFrames() { return mNumberFrames; } 16 | 17 | void GrabAudioData(AudioBufferList *inBL); 18 | Boolean ComputeFFT(int32_t *outFFTData); 19 | 20 | private: 21 | volatile int32_t mNeedsAudioData; 22 | volatile int32_t mHasAudioData; 23 | 24 | H_SPECTRUM_ANALYSIS mSpectrumAnalysis; 25 | 26 | int32_t* mAudioBuffer; 27 | UInt32 mNumberFrames; 28 | UInt32 mAudioBufferSize; 29 | int32_t mAudioBufferCurrentIndex; 30 | }; -------------------------------------------------------------------------------- /Ultrasound/FFTBufferManager.mm: -------------------------------------------------------------------------------- 1 | // 2 | // FFTBufferManager.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/25/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "FFTBufferManager.h" 10 | #import "FFTAccelerate.h" 11 | 12 | @implementation FFTBufferManager 13 | { 14 | int index; 15 | int size; 16 | int *buffer; 17 | 18 | FFTAccelerate *accel; 19 | } 20 | 21 | - (instancetype) initWithSize:(int)s 22 | { 23 | if(self = [super init]) 24 | { 25 | size = s; 26 | buffer = (int *)malloc(size * sizeof(int)); 27 | accel = new FFTAccelerate(s); 28 | } 29 | return self; 30 | } 31 | 32 | - (void) addFrames:(AudioBufferList *)bl 33 | { 34 | UInt32 bytesToCopy = MIN(bl->mBuffers[0].mDataByteSize, (size - index) * sizeof(int)); 35 | memcpy(buffer+index, bl->mBuffers[0].mData, bytesToCopy); 36 | 37 | index += bytesToCopy / sizeof(int); 38 | if (index >= size) 39 | { 40 | // Audio data is full, can now process data... 41 | printf("Processing data!!!"); 42 | float *normalized = (float *)malloc(size * sizeof(float)); 43 | for (int i = 0; i < size; i++) 44 | { 45 | normalized[i] = buffer[i] / INT32_MAX; 46 | } 47 | 48 | float *tmp = (float *)malloc(size * sizeof(float)); 49 | accel->doFFTReal(normalized, tmp, size); 50 | 51 | for (int i = 0; i < size; i++) 52 | { 53 | printf("%d,%f\n", i, tmp[i]); 54 | } 55 | 56 | printf("Done processing data!!!"); 57 | 58 | } 59 | } 60 | 61 | - (void) doFFT:(int **)result 62 | { 63 | 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Ultrasound/FFTGraphView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FFTGraphView.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/26/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "GraphView.h" 10 | 11 | @interface FFTGraphView : GraphView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Ultrasound/FFTGraphView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FFTGraphView.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/26/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "FFTGraphView.h" 10 | 11 | @implementation FFTGraphView 12 | 13 | - (Transforms) initialTransforms 14 | { 15 | Transforms trans = [super initialTransforms]; 16 | 17 | trans.translation.x = 20000; 18 | trans.translation.y = 100; 19 | 20 | trans.scale.x = self.frame.size.width / 6000.0; 21 | trans.scale.y = self.frame.size.height / 200.0; 22 | 23 | return trans; 24 | } 25 | 26 | - (CGPoint) tickMarkSpacing 27 | { 28 | return CGPointMake(1000, 20); 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Ultrasound/GraphView.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "GraphViewUtils.h" 4 | 5 | 6 | @class GraphView; 7 | @protocol GraphViewDataSource 8 | - (double) valueForXCoord:(double)x withIndex:(int) index graphView:(GraphView *)view; 9 | @end 10 | 11 | @interface GraphView : UIView 12 | 13 | @property (nonatomic, weak) id dataSource; 14 | @property (nonatomic) float minRedrawInterval; 15 | - (void) setupInitialTransforms; 16 | - (void) generateBitmapAndRedraw; 17 | 18 | 19 | // Methods to override 20 | - (Transforms) initialTransforms; 21 | - (CGPoint) tickMarkSpacing; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Ultrasound/GraphView.m: -------------------------------------------------------------------------------- 1 | 2 | #import "GraphView.h" 3 | #import 4 | #import 5 | 6 | @interface GraphView() 7 | @property (nonatomic) Transforms transforms; 8 | @property (nonatomic) BOOL doesNotNeedToLoadUserDefaults; 9 | @property (nonatomic) CGPoint topLeftCartesianCoordinateOfFunctionBitmap; 10 | @property (nonatomic) CGPoint scaleAtTimeOfBitmapRender; 11 | @property (nonatomic) NSTimeInterval lastBitmapGenerationTime; 12 | @end 13 | 14 | @implementation GraphView 15 | { 16 | CGImageRef offscreenImage; 17 | } 18 | @synthesize dataSource = _dataSource, transforms = _transforms, doesNotNeedToLoadUserDefaults = _doesNotNeedToLoadUserDefaults; 19 | 20 | - (CGPoint) center 21 | { 22 | return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); 23 | } 24 | 25 | - (Transforms) transforms 26 | { 27 | if(!self.doesNotNeedToLoadUserDefaults) 28 | { 29 | //_transforms = [GraphViewUtils loadSavedTransforms]; 30 | _transforms = [self initialTransforms]; 31 | self.doesNotNeedToLoadUserDefaults = YES; 32 | } 33 | 34 | Transforms output = _transforms; 35 | if(output.scale.x == 0) 36 | { 37 | output.scale.x = 40; 38 | } 39 | if(output.scale.y == 0) 40 | { 41 | output.scale.y = 40; 42 | } 43 | 44 | output.center = [self center]; 45 | 46 | return output; 47 | } 48 | 49 | - (Transforms) initialTransforms 50 | { 51 | Transforms output; 52 | 53 | output.scale.x = self.frame.size.width / 2; 54 | output.scale.y = self.frame.size.height / 2; 55 | 56 | output.translation.y = 0; 57 | output.translation.x = 0; 58 | 59 | output.center = [self center]; 60 | 61 | return output; 62 | 63 | } 64 | 65 | - (CGPoint) tickMarkSpacing 66 | { 67 | return CGPointMake(1, 1); 68 | } 69 | 70 | 71 | - (void) setTransforms:(Transforms)transforms 72 | { 73 | _transforms.scale = transforms.scale; 74 | _transforms.translation = transforms.translation; 75 | 76 | [self setNeedsDisplay]; 77 | } 78 | 79 | 80 | 81 | - (void) setupInitialTransforms 82 | { 83 | self.transforms = [self initialTransforms]; 84 | self.minRedrawInterval = 0.4; 85 | } 86 | 87 | 88 | - (void) drawGrid:(CGContextRef) ref withXIncrement:(double)xIncrement withYIncrement:(double)yIncrement 89 | { 90 | UIGraphicsPushContext(ref); 91 | 92 | 93 | #define kTickHeightX 2.0 94 | 95 | // X Axis 96 | CGPoint leftScreen = CGPointMake(0, 0); 97 | double leftCart = [GraphViewUtils convertPixelToCartesian:leftScreen withTransforms:self.transforms].x - ((int)self.transforms.translation.x % (int)xIncrement); 98 | 99 | 100 | CGPoint rightScreen = CGPointMake(self.frame.size.width, 0); 101 | double rightCart = [GraphViewUtils convertPixelToCartesian:rightScreen withTransforms:self.transforms].x - ((int)self.transforms.translation.x % (int)xIncrement); 102 | 103 | leftCart = floor(leftCart); 104 | rightCart = ceil(rightCart); 105 | 106 | 107 | 108 | // Start the path! 109 | CGContextBeginPath(ref); 110 | 111 | for(double i = leftCart; i <= rightCart; i += xIncrement) 112 | { 113 | 114 | CGPoint topCartesian = CGPointMake(i, kTickHeightX/2.0); 115 | CGPoint bottomCartesian = CGPointMake(i, -kTickHeightX/2.0); 116 | 117 | CGPoint topPixelCoord = [GraphViewUtils convertCartesianToPixel:topCartesian withTransforms:self.transforms]; 118 | CGPoint bottomPixelCoord = [GraphViewUtils convertCartesianToPixel:bottomCartesian withTransforms:self.transforms]; 119 | topPixelCoord.y = self.frame.size.height - 12.5; 120 | bottomPixelCoord.y = topPixelCoord.y + 25; 121 | 122 | CGPoint labelPosition = CGPointMake(topPixelCoord.x - 10, topPixelCoord.y - 15); 123 | if ((ABS(i) > 0.0001)) 124 | { 125 | NSString *xValueLabel = [NSString stringWithFormat:@"%g", i]; 126 | [xValueLabel drawAtPoint:labelPosition withFont:[UIFont systemFontOfSize:12.0f]]; 127 | } 128 | else 129 | { 130 | NSString *xValueLabel = [NSString stringWithFormat:@"%i", 0]; 131 | [xValueLabel drawAtPoint:labelPosition withFont:[UIFont systemFontOfSize:12.0f]]; 132 | } 133 | 134 | CGContextMoveToPoint(ref, topPixelCoord.x, topPixelCoord.y); 135 | CGContextAddLineToPoint(ref, bottomPixelCoord.x, bottomPixelCoord.y - 7.5); 136 | } 137 | 138 | 139 | #define kTickHeightY 0.01 140 | // Y Axis 141 | CGPoint topScreen = CGPointMake(0, 0); 142 | double topCart = [GraphViewUtils convertPixelToCartesian:topScreen withTransforms:self.transforms].y; 143 | 144 | 145 | CGPoint bottomScreen = CGPointMake(0, self.frame.size.height); 146 | double bottomCart = [GraphViewUtils convertPixelToCartesian:bottomScreen withTransforms:self.transforms].y; 147 | 148 | bottomCart = floor(bottomCart / yIncrement) * yIncrement; 149 | topCart = ceil(topCart / yIncrement) * yIncrement; 150 | 151 | for(double i = bottomCart; i <= topCart; i += yIncrement) 152 | { 153 | CGPoint leftCartesian = CGPointMake(-kTickHeightY/2.0, i); 154 | CGPoint rightCartesian = CGPointMake(kTickHeightY/2.0, i); 155 | 156 | CGPoint leftPixelCoord = [GraphViewUtils convertCartesianToPixel:leftCartesian withTransforms:self.transforms]; 157 | CGPoint rightPixelCoord = [GraphViewUtils convertCartesianToPixel:rightCartesian withTransforms:self.transforms]; 158 | float width = 20; 159 | leftPixelCoord.x = 0; 160 | rightPixelCoord.x = leftPixelCoord.x + width; 161 | if ((ABS(i) > 0.0001)) 162 | { 163 | CGPoint labelPosition = CGPointMake(rightPixelCoord.x + width / 2, leftPixelCoord.y - 8); 164 | NSString *yValueLabel = [NSString stringWithFormat:@"%g", i]; 165 | [yValueLabel drawAtPoint:labelPosition withFont:[UIFont systemFontOfSize:12.0f]]; 166 | } 167 | else 168 | { 169 | CGPoint labelPosition = CGPointMake(rightPixelCoord.x + width / 2, leftPixelCoord.y - 8); 170 | NSString *yValueLabel = [NSString stringWithFormat:@"%i", 0]; 171 | [yValueLabel drawAtPoint:labelPosition withFont:[UIFont systemFontOfSize:12.0f]]; 172 | } 173 | 174 | CGContextMoveToPoint(ref, leftPixelCoord.x, leftPixelCoord.y); 175 | CGContextAddLineToPoint(ref, rightPixelCoord.x, rightPixelCoord.y); 176 | } 177 | 178 | CGContextDrawPath(ref, kCGPathStroke); // Done drawing each grid line 179 | 180 | UIGraphicsPopContext(); 181 | } 182 | 183 | 184 | bool hadRecentNan; 185 | - (void) drawGraph:(CGContextRef) c withIndex:(int)index 186 | { 187 | UIGraphicsPushContext(c); 188 | CGContextBeginPath(c); 189 | 190 | for(int i = 0 ; i <= self.frame.size.width; i++) 191 | { 192 | CGPoint convertedToCart = [GraphViewUtils convertPixelToCartesian:CGPointMake(i, 0) withTransforms:self.transforms]; 193 | convertedToCart.y = [self.dataSource valueForXCoord:convertedToCart.x withIndex:index graphView:self]; 194 | //convertedToCart.x *= 2.0*M_PI; 195 | 196 | if(isnan(convertedToCart.y) || isinf(convertedToCart.y)) 197 | { 198 | hadRecentNan = YES; 199 | continue; 200 | } 201 | 202 | CGPoint finalPixelPosition = [GraphViewUtils convertCartesianToPixel:convertedToCart withTransforms:self.transforms]; 203 | 204 | if(i == 0) 205 | { 206 | CGContextMoveToPoint(c, finalPixelPosition.x, finalPixelPosition.y); 207 | } 208 | else 209 | { 210 | if(hadRecentNan) 211 | { 212 | CGContextMoveToPoint(c, finalPixelPosition.x, finalPixelPosition.y); 213 | hadRecentNan = NO; 214 | } 215 | else 216 | { 217 | CGContextAddLineToPoint(c, finalPixelPosition.x, finalPixelPosition.y); 218 | } 219 | } 220 | } 221 | 222 | // S11 = 0 223 | // S21 = 1 224 | // S11 (Changed load) = 2 225 | // S21 (Changed load) = 3 226 | 227 | CGContextSetLineWidth(c, 1.5); 228 | 229 | 230 | 231 | switch (index) 232 | { 233 | case 0: 234 | CGContextSetRGBStrokeColor(c, 0.0, 1.0, 0.0, 0.8); 235 | 236 | break; 237 | case 1: 238 | CGContextSetRGBStrokeColor(c, 0.0, 1.0, 1.0, 1.0); 239 | 240 | break; 241 | case 2: 242 | CGContextSetRGBStrokeColor(c, 0.0, 1.0, 0.0, 0.8); 243 | 244 | CGFloat dash1[2] = {8, 2}; 245 | CGContextSetLineDash(c, 0, dash1, 2); 246 | break; 247 | case 3: 248 | CGContextSetRGBStrokeColor(c, 0.0, 1.0, 1.0, 1.0); 249 | 250 | CGFloat dash2[2] = {8, 2}; 251 | CGContextSetLineDash(c, 0, dash2, 2); 252 | break; 253 | default: 254 | CGContextSetRGBStrokeColor(c, 0.0, 0, 0, 0.0); 255 | break; 256 | } 257 | 258 | CGContextDrawPath(c, kCGPathStroke); 259 | UIGraphicsPopContext(); 260 | } 261 | 262 | - (void) drawAllFunctions:(CGContextRef)c 263 | { 264 | [self drawGraph:c withIndex:0]; 265 | [self drawGraph:c withIndex:1]; 266 | } 267 | 268 | - (void) drawCachedFunctionImage:(CGContextRef)c 269 | { 270 | if(offscreenImage == NULL) 271 | { 272 | [self generateBitmap]; 273 | } 274 | 275 | 276 | CGPoint topLeftPixelCoordinateOfBitmap = [GraphViewUtils convertCartesianToPixel:self.topLeftCartesianCoordinateOfFunctionBitmap withTransforms:self.transforms]; 277 | CGRect imageRect; 278 | imageRect.origin = topLeftPixelCoordinateOfBitmap; 279 | imageRect.size = self.bounds.size; 280 | 281 | CGPoint scaleRatio; 282 | scaleRatio.x = self.transforms.scale.x / self.scaleAtTimeOfBitmapRender.x; 283 | scaleRatio.y = self.transforms.scale.y / self.scaleAtTimeOfBitmapRender.y; 284 | 285 | 286 | 287 | imageRect.size.width *= scaleRatio.x; 288 | imageRect.size.height *= scaleRatio.y; 289 | 290 | 291 | 292 | 293 | CGContextDrawImage(c, imageRect, offscreenImage); 294 | } 295 | 296 | - (void)drawRect:(CGRect)rect 297 | { 298 | //self.translations.y = -(self.frame.size.height / 2.0) / output.scale.y; 299 | // Transforms transforms = self.transforms; 300 | // transforms.translation.y = (self.frame.size.height / 2.0) / self.transforms.scale.y; 301 | // self.transforms = transforms; 302 | 303 | CGContextRef c = UIGraphicsGetCurrentContext(); 304 | 305 | const CGFloat colors[] = {0.8, 0.8, 0.8, 1.0}; 306 | CGContextSetStrokeColor(c, colors); 307 | CGContextSetFillColor(c, colors); 308 | 309 | CGPoint spacing = [self tickMarkSpacing]; 310 | [self drawGrid:c withXIncrement:spacing.x withYIncrement:spacing.y]; 311 | 312 | [self drawCachedFunctionImage:c]; 313 | } 314 | 315 | 316 | - (void) generateBitmapAndRedraw 317 | { 318 | NSTimeInterval currentTime = CACurrentMediaTime(); 319 | 320 | if(currentTime - self.lastBitmapGenerationTime >= self.minRedrawInterval) 321 | { 322 | [self generateBitmap]; 323 | [self setNeedsDisplay]; 324 | } 325 | } 326 | 327 | 328 | - (void) generateBitmap 329 | { 330 | NSTimeInterval currentTime = CACurrentMediaTime(); 331 | 332 | if(currentTime - self.lastBitmapGenerationTime >= self.minRedrawInterval) 333 | { 334 | CGImageRelease(offscreenImage); 335 | void *data; 336 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 337 | CGContextRef bitmapContext = createBitmapContext((int)self.frame.size.width, (int)self.frame.size.height, &data); 338 | [self drawAllFunctions:bitmapContext]; 339 | 340 | offscreenImage = CGBitmapContextCreateImage(bitmapContext); 341 | CGColorSpaceRelease(colorSpace); 342 | CFRelease(bitmapContext); 343 | free(data); 344 | CGPoint topLeft = CGPointMake(0, 0); 345 | self.topLeftCartesianCoordinateOfFunctionBitmap = [GraphViewUtils convertPixelToCartesian:topLeft withTransforms:self.transforms]; 346 | self.scaleAtTimeOfBitmapRender = self.transforms.scale; 347 | 348 | self.lastBitmapGenerationTime = currentTime; 349 | } 350 | else 351 | { 352 | // [self performSelector:@selector(generateBitmapAndRedraw) withObject:nil afterDelay:1.0]; 353 | } 354 | } 355 | 356 | 357 | 358 | 359 | CGContextRef createBitmapContext (int pixelsWide, int pixelsHigh, void **bitmapData) 360 | { 361 | CGContextRef context = NULL; 362 | CGColorSpaceRef colorSpace; 363 | int bitmapByteCount; 364 | int bitmapBytesPerRow; 365 | 366 | bitmapBytesPerRow = (pixelsWide * 4); // 1 367 | bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); 368 | 369 | colorSpace = CGColorSpaceCreateDeviceRGB(); // 2 370 | *bitmapData = malloc(bitmapByteCount); // 3 371 | if (*bitmapData == NULL) 372 | { 373 | fprintf (stderr, "Memory not allocated!"); 374 | return NULL; 375 | } 376 | // 4 377 | context = CGBitmapContextCreate(*bitmapData, 378 | pixelsWide, 379 | pixelsHigh, 380 | 8, // Bits per component 381 | bitmapBytesPerRow, 382 | colorSpace, 383 | kCGImageAlphaPremultipliedLast); 384 | if (context== NULL) 385 | { 386 | free (*bitmapData); // 5 387 | fprintf (stderr, "Context not created!"); 388 | return NULL; 389 | } 390 | CGColorSpaceRelease(colorSpace); // 6 391 | 392 | return context; // 7 393 | } 394 | 395 | 396 | 397 | 398 | // Touch event handlers 399 | #define kHorizontalThreshold 10.0 400 | #define kVerticalThreshold 80.0 401 | - (void)handlePinch:(UIPinchGestureRecognizer *) pinch 402 | { 403 | if (pinch.state == UIGestureRecognizerStateChanged) 404 | { 405 | CGFloat pinchSize = pinch.scale; 406 | Transforms newTransforms = self.transforms; 407 | 408 | if(pinch.numberOfTouches < 2) 409 | { 410 | pinch.scale = 1; 411 | return; 412 | } 413 | 414 | CGPoint touch1 = [pinch locationOfTouch:0 inView:self]; 415 | CGPoint touch2 = [pinch locationOfTouch:1 inView:self]; 416 | 417 | float dx = ABS(touch2.x - touch1.x); 418 | float dy = ABS(touch2.y - touch1.y); 419 | 420 | float angle = atan(dy / dx); 421 | 422 | if(angle <= kHorizontalThreshold * (M_PI / 180.0)) 423 | { 424 | newTransforms.scale.x *= pinchSize; 425 | } 426 | else if(angle >= kVerticalThreshold * (M_PI / 180.0)) 427 | { 428 | newTransforms.scale.y *= pinchSize; 429 | } 430 | else 431 | { 432 | newTransforms.scale.x *= pinchSize; 433 | newTransforms.scale.y *= pinchSize; 434 | } 435 | 436 | 437 | 438 | 439 | self.transforms = newTransforms; 440 | 441 | pinch.scale = 1; 442 | 443 | return; 444 | } 445 | 446 | if(pinch.state == UIGestureRecognizerStateEnded) 447 | { 448 | CGFloat pinchSize = pinch.scale; 449 | Transforms newTransforms = self.transforms; 450 | newTransforms.scale.x *= pinchSize; 451 | newTransforms.scale.y *= pinchSize; 452 | 453 | [self generateBitmap]; 454 | 455 | self.transforms = newTransforms; 456 | 457 | pinch.scale = 1; 458 | 459 | [GraphViewUtils saveTransforms:self.transforms]; 460 | } 461 | } 462 | 463 | - (void)handlePan:(UIPanGestureRecognizer *) pan 464 | { 465 | if (pan.state == UIGestureRecognizerStateChanged) 466 | { 467 | CGPoint translation = [GraphViewUtils multiplyPoint:[pan translationInView:self] withScalar:-1]; 468 | //tran 469 | CGPoint currentTranslationAsPixels = [GraphViewUtils convertCartesianToPixel:self.transforms.translation withTransforms:self.transforms]; 470 | 471 | Transforms newTransforms = self.transforms; 472 | newTransforms.translation = [GraphViewUtils addPoint:currentTranslationAsPixels with:translation]; 473 | newTransforms.translation = [GraphViewUtils convertPixelToCartesian:newTransforms.translation withTransforms:self.transforms]; 474 | 475 | self.transforms = newTransforms; 476 | 477 | [pan setTranslation:CGPointZero inView:self]; 478 | 479 | return; 480 | } 481 | 482 | if(pan.state == UIGestureRecognizerStateEnded) 483 | { 484 | CGPoint translation = [GraphViewUtils multiplyPoint:[pan translationInView:self] withScalar:-1]; 485 | //tran 486 | CGPoint currentTranslationAsPixels = [GraphViewUtils convertCartesianToPixel:self.transforms.translation withTransforms:self.transforms]; 487 | 488 | Transforms newTransforms = self.transforms; 489 | newTransforms.translation = [GraphViewUtils addPoint:currentTranslationAsPixels with:translation]; 490 | newTransforms.translation = [GraphViewUtils convertPixelToCartesian:newTransforms.translation withTransforms:self.transforms]; 491 | 492 | [self generateBitmap]; 493 | 494 | self.transforms = newTransforms; 495 | 496 | [pan setTranslation:CGPointZero inView:self]; 497 | 498 | [GraphViewUtils saveTransforms:self.transforms]; 499 | } 500 | } 501 | 502 | 503 | 504 | - (void) layoutSubviews 505 | { 506 | [super layoutSubviews]; 507 | 508 | [self generateBitmapAndRedraw]; 509 | } 510 | 511 | @end -------------------------------------------------------------------------------- /Ultrasound/GraphViewUtils.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "Transforms.h" 4 | 5 | @interface GraphViewUtils : NSObject 6 | 7 | + (CGPoint) convertCartesianToPixel:(CGPoint)cart withTransforms:(Transforms)transforms; 8 | 9 | + (CGPoint) convertPixelToCartesian:(CGPoint)pixel withTransforms:(Transforms)transforms; 10 | 11 | + (CGPoint) addPoint:(CGPoint)p0 with:(CGPoint) p1; 12 | + (CGPoint) multiplyPoint:(CGPoint)p0 withScalar:(CGFloat)s; 13 | 14 | + (Transforms) loadSavedTransforms; 15 | + (void) saveTransforms:(Transforms) transforms; 16 | @end 17 | -------------------------------------------------------------------------------- /Ultrasound/GraphViewUtils.m: -------------------------------------------------------------------------------- 1 | 2 | #import "GraphViewUtils.h" 3 | 4 | @implementation GraphViewUtils 5 | 6 | //TODO: Divide by (2*M_PI) 7 | + (CGPoint) convertCartesianToPixel:(CGPoint)p withTransforms:(Transforms)transforms 8 | { 9 | CGPoint cart = [self addPoint:p with:[self multiplyPoint:transforms.translation withScalar:-1]]; 10 | 11 | CGPoint point = transforms.center; 12 | point.x += cart.x * transforms.scale.x; 13 | point.y += -cart.y * transforms.scale.y; 14 | 15 | return point; 16 | } 17 | 18 | + (CGPoint) convertPixelToCartesian:(CGPoint)p withTransforms:(Transforms)transforms 19 | { 20 | double xDiff = (p.x-transforms.center.x) / transforms.scale.x; // Find difference between center of screen and pixel, then scale 21 | double yDiff = -(p.y-transforms.center.y) / transforms.scale.y; 22 | CGPoint point = CGPointMake(xDiff, yDiff); 23 | 24 | 25 | point = [self addPoint:point with:transforms.translation]; // Apply translation 26 | 27 | return point; 28 | } 29 | 30 | + (CGPoint) addPoint:(CGPoint)p0 with:(CGPoint) p1 31 | { 32 | return CGPointMake(p0.x + p1.x, p0.y + p1.y); 33 | } 34 | 35 | + (CGPoint) multiplyPoint:(CGPoint)p0 withScalar:(CGFloat)s 36 | { 37 | return CGPointMake(p0.x * s, p0.y * s); 38 | } 39 | 40 | + (Transforms) loadSavedTransforms 41 | { 42 | NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults]; 43 | 44 | CGPoint scale = CGPointMake([savedData doubleForKey:@"scale_x"], [savedData doubleForKey:@"scale_y"]); 45 | CGPoint translation = CGPointMake([savedData doubleForKey:@"trans_x"], [savedData doubleForKey:@"trans_y"]); 46 | 47 | Transforms transform; 48 | transform.scale = scale; 49 | transform.translation = translation; 50 | 51 | return transform; 52 | } 53 | 54 | + (void) saveTransforms:(Transforms)transforms 55 | { 56 | NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults]; 57 | [savedData setDouble:transforms.scale.x forKey:@"scale_x"]; 58 | [savedData setDouble:transforms.scale.y forKey:@"scale_y"]; 59 | 60 | [savedData setDouble:transforms.translation.x forKey:@"trans_x"]; 61 | [savedData setDouble:transforms.translation.y forKey:@"trans_y"]; 62 | } 63 | @end 64 | -------------------------------------------------------------------------------- /Ultrasound/NSArray+Levenshtein.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Levenshtein.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 8/2/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (Levenshtein) 12 | - (NSUInteger)levenshteinDistanceToArray:(NSArray *)array; 13 | - (double)percentErrorToReceivedArray:(NSArray *)array; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Ultrasound/NSArray+Levenshtein.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Levenshtein.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 8/2/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "NSArray+Levenshtein.h" 10 | #import "NSString+Levenshtein.h" 11 | 12 | @implementation NSArray (Levenshtein) 13 | - (NSUInteger)levenshteinDistanceToArray:(NSArray *)array 14 | { 15 | NSString *selfString = [self arrayToString:self]; 16 | NSString *otherString = [self arrayToString:array]; 17 | 18 | return [selfString levenshteinDistanceToString:otherString]; 19 | } 20 | 21 | - (double)percentErrorToReceivedArray:(NSArray *)array 22 | { 23 | int wc = 0; 24 | for(int i = 0; i < self.count; i++) 25 | { 26 | if(i >= array.count) 27 | { 28 | wc++; 29 | } 30 | else if([self[i] intValue] != [array[i] intValue]) 31 | { 32 | wc++; 33 | } 34 | } 35 | wc += MAX((int)array.count - (int)self.count, 0); 36 | 37 | return (double)wc / self.count; 38 | } 39 | 40 | - (NSString *) arrayToString:(NSArray *)array 41 | { 42 | NSMutableString *string = [NSMutableString stringWithCapacity:array.count]; 43 | 44 | for (NSNumber *num in array) 45 | { 46 | [string appendFormat:@"%d", num.intValue]; 47 | } 48 | return string; 49 | } 50 | @end 51 | -------------------------------------------------------------------------------- /Ultrasound/NSData+AES256.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+AES256.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 8/6/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSData (AES256) 12 | 13 | - (NSData *)AES256EncryptWithKey:(NSString *)key; 14 | - (NSData *)AES256DecryptWithKey:(NSString *)key; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Ultrasound/NSData+AES256.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+AES256.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 8/6/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "NSData+AES256.h" 10 | #import 11 | 12 | @implementation NSData (AES256) 13 | 14 | - (NSData *)AES256EncryptWithKey:(NSString *)key { 15 | // 'key' should be 32 bytes for AES256, will be null-padded otherwise 16 | char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused) 17 | bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 18 | 19 | // fetch key data 20 | [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 21 | 22 | NSUInteger dataLength = [self length]; 23 | 24 | //See the doc: For block ciphers, the output size will always be less than or 25 | //equal to the input size plus the size of one block. 26 | //That's why we need to add the size of one block here 27 | size_t bufferSize = dataLength + kCCBlockSizeAES128; 28 | void *buffer = malloc(bufferSize); 29 | 30 | size_t numBytesEncrypted = 0; 31 | CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 32 | keyPtr, kCCKeySizeAES256, 33 | NULL /* initialization vector (optional) */, 34 | [self bytes], dataLength, /* input */ 35 | buffer, bufferSize, /* output */ 36 | &numBytesEncrypted); 37 | if (cryptStatus == kCCSuccess) { 38 | //the returned NSData takes ownership of the buffer and will free it on deallocation 39 | return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 40 | } 41 | 42 | free(buffer); //free the buffer; 43 | return nil; 44 | } 45 | 46 | - (NSData *)AES256DecryptWithKey:(NSString *)key { 47 | // 'key' should be 32 bytes for AES256, will be null-padded otherwise 48 | char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused) 49 | bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 50 | 51 | // fetch key data 52 | [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 53 | 54 | NSUInteger dataLength = [self length]; 55 | 56 | //See the doc: For block ciphers, the output size will always be less than or 57 | //equal to the input size plus the size of one block. 58 | //That's why we need to add the size of one block here 59 | size_t bufferSize = dataLength + kCCBlockSizeAES128; 60 | void *buffer = malloc(bufferSize); 61 | 62 | size_t numBytesDecrypted = 0; 63 | CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 64 | keyPtr, kCCKeySizeAES256, 65 | NULL /* initialization vector (optional) */, 66 | [self bytes], dataLength, /* input */ 67 | buffer, bufferSize, /* output */ 68 | &numBytesDecrypted); 69 | 70 | if (cryptStatus == kCCSuccess) { 71 | //the returned NSData takes ownership of the buffer and will free it on deallocation 72 | return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; 73 | } 74 | 75 | free(buffer); //free the buffer; 76 | return nil; 77 | } 78 | 79 | @end -------------------------------------------------------------------------------- /Ultrasound/NSString+Levenshtein.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface NSString (Levenshtein) 5 | - (NSUInteger)levenshteinDistanceToString:(NSString *)string; 6 | - (float)percentCorrectToString:(NSString *)string; 7 | @end -------------------------------------------------------------------------------- /Ultrasound/NSString+Levenshtein.m: -------------------------------------------------------------------------------- 1 | 2 | #import "NSString+Levenshtein.h" 3 | 4 | @implementation NSString (Levenshtein) 5 | - (NSUInteger)levenshteinDistanceToString:(NSString *)string 6 | { 7 | NSUInteger sl = [self length]; 8 | NSUInteger tl = [string length]; 9 | NSUInteger *d = calloc(sizeof(*d), (sl+1) * (tl+1)); 10 | 11 | #define d(i, j) d[((j) * sl) + (i)] 12 | for (NSUInteger i = 0; i <= sl; i++) { 13 | d(i, 0) = i; 14 | } 15 | for (NSUInteger j = 0; j <= tl; j++) { 16 | d(0, j) = j; 17 | } 18 | for (NSUInteger j = 1; j <= tl; j++) { 19 | for (NSUInteger i = 1; i <= sl; i++) { 20 | if ([self characterAtIndex:i-1] == [string characterAtIndex:j-1]) { 21 | d(i, j) = d(i-1, j-1); 22 | } else { 23 | d(i, j) = MIN(d(i-1, j), MIN(d(i, j-1), d(i-1, j-1))) + 1; 24 | } 25 | } 26 | } 27 | 28 | NSUInteger r = d(sl, tl); 29 | #undef d 30 | 31 | free(d); 32 | 33 | return r; 34 | } 35 | 36 | - (float) percentCorrectToString:(NSString *)string 37 | { 38 | int dist = [self levenshteinDistanceToString:string]; 39 | 40 | int minDist = ABS(self.length - string.length); 41 | int maxDist = MAX(self.length, string.length); 42 | int minMaxDist = maxDist - minDist; 43 | if(minMaxDist == 0) 44 | { 45 | return 1; 46 | } 47 | 48 | return 1.0 - ((float)(dist - minDist) / (float)minMaxDist); 49 | } 50 | @end -------------------------------------------------------------------------------- /Ultrasound/ProcessAlgoMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessAlgoMain.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/5/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ProcessAlgoMain : NSObject 12 | 13 | + (float) getDistanceSpacingFallback:(NSArray *) packetData andDistancesIntoArray:(NSArray **)distances; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Ultrasound/ProcessAlgoMain.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessAlgoMain.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/5/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "ProcessAlgoMain.h" 10 | #import "ProcessingFunctions.h" 11 | #import "Clump.h" 12 | #import "AudioPlayer.h" 13 | 14 | 15 | #define NSLog(x) 16 | #define printArray(x) 17 | #define printArrayWithIndices(x) 18 | 19 | @implementation ProcessAlgoMain 20 | + (float) getDistanceSpacingFallback:(NSArray *) packetData andDistancesIntoArray:(NSArray **)distances 21 | { 22 | NSArray *firstDerivative = differentiate(packetData, 2); 23 | 24 | NSArray *cutoffFirstDeriv = cutoffData(multiplyArrayByConstant(firstDerivative, 10), 0.5); 25 | printArrayWithIndices(cutoffFirstDeriv); 26 | 27 | 28 | NSArray *mergedDeriv = mergeGaps(cutoffFirstDeriv, 4); 29 | // printArray(mergedLowPassedSecondDeriv); 30 | 31 | NSArray *clumpIndices = findMidpointsOfClumps(mergedDeriv); 32 | NSLog(@"-------Clump indices-----"); 33 | // printArray(clumpIndices); 34 | *distances = findDistances(clumpIndices); 35 | 36 | 37 | NSArray *distanceClumps = clumpData(*distances, 12); 38 | distanceClumps = [distanceClumps sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { 39 | double val1 = [obj1 average]; 40 | double val2 = [obj2 average]; 41 | 42 | if (val2 > val1) 43 | { 44 | return NSOrderedAscending; 45 | } 46 | else if(val2 < val1) 47 | { 48 | return NSOrderedDescending; 49 | } 50 | else 51 | { 52 | return NSOrderedSame; 53 | } 54 | }]; 55 | 56 | 57 | printArray(distanceClumps); 58 | 59 | double defaultClumpLength = 30.0 * (kTransmitInterval / 0.6); 60 | if(distanceClumps.count == 0) 61 | { 62 | return defaultClumpLength; 63 | } 64 | 65 | // Find the clump whose average is closest to the experimentally determined splitting value of 30 66 | int closestClump; 67 | double minDiff = DBL_MAX; 68 | for (int i = 0; i < distanceClumps.count; i++) 69 | { 70 | double average = [distanceClumps[i] average]; 71 | double diff = abs(average - defaultClumpLength); 72 | if (diff < minDiff) 73 | { 74 | minDiff = diff; 75 | closestClump = i; 76 | } 77 | } 78 | 79 | float fallbackDistance = [distanceClumps[closestClump] average]; 80 | 81 | // Add on the last distance value 82 | int lastClumpIndex = [[clumpIndices lastObject] intValue]; 83 | int lastDataIndex = packetData.count - 1; 84 | int lastDistance = lastDataIndex - lastClumpIndex; 85 | if(lastDistance >= fallbackDistance * 0.5) 86 | { 87 | *distances = [*distances arrayByAddingObject:@(lastDistance)]; 88 | } 89 | NSLog(@"-------Distances-----"); 90 | // printArray(*distances); 91 | 92 | //printf("%f", distance); 93 | return fallbackDistance; 94 | } 95 | @end 96 | -------------------------------------------------------------------------------- /Ultrasound/ProcessingFunctions.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingFunctions.h 3 | // ProcessAlgo 4 | // 5 | // Created by AppDev on 7/4/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define kProcessingLowPassFilterConstant 0.5 12 | #define kProcessingSecondDerivCutoff 4.0 13 | 14 | 15 | NSArray *multiplyArrayByConstant(NSArray *data, double k); 16 | int getMinGap(NSArray *data); 17 | NSArray *differentiate(NSArray *data, int accuracy); 18 | NSArray *doLowPass(NSArray *data, double k); 19 | void printArrayWithIndices(NSArray *array); 20 | void printArray(NSArray *array); 21 | NSArray *cutoffData(NSArray *data, double cutoff); 22 | NSArray *mergeGaps(NSArray *data, int maxWidth); 23 | NSArray *findMidpointsOfClumps(NSArray *data); 24 | NSArray *findDistances(NSArray *data); 25 | NSArray *clumpData(NSArray *data, int tolerance); 26 | 27 | 28 | -------------------------------------------------------------------------------- /Ultrasound/ProcessingFunctions.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingFunctions.c 3 | // ProcessAlgo 4 | // 5 | // Created by AppDev on 7/4/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #include 10 | #import 11 | #import "ProcessingFunctions.h" 12 | #import "Clump.h" 13 | 14 | 15 | void printArrayWithIndices(NSArray *array) 16 | { 17 | for(int i = 0; i < array.count; i++) 18 | { 19 | printf("%d,%f\n", i, [array[i] doubleValue]); 20 | } 21 | } 22 | 23 | NSArray *doLowPass(NSArray *data, double k) 24 | { 25 | NSMutableArray *lowPassData = [NSMutableArray arrayWithCapacity:data.count]; 26 | double lastValue = [data[0] doubleValue]; 27 | for(int i = 0; i < data.count; i++) 28 | { 29 | // val = lastVal * k + currVal * (1-k) 30 | double currentValue = [data[i] doubleValue]; 31 | double filteredVal = (lastValue * k) + (currentValue * (1 - k)); 32 | [lowPassData addObject:@(filteredVal)]; 33 | lastValue = filteredVal; 34 | } 35 | return lowPassData; 36 | } 37 | 38 | NSArray *differentiate(NSArray *data, int accuracy) 39 | { 40 | NSMutableArray *derivative = [NSMutableArray arrayWithCapacity:data.count]; 41 | for(int i = 0; i < data.count; i++) 42 | { 43 | double leftVal = 0; 44 | double rightVal = 0; 45 | double dx = 0; 46 | if(i <= accuracy-1) 47 | { 48 | leftVal = [data[i] doubleValue]; 49 | rightVal = [data[MIN(i + accuracy, data.count-1)] doubleValue]; 50 | dx = accuracy; 51 | } 52 | else if(i >= data.count - accuracy) 53 | { 54 | leftVal = [data[i-accuracy] doubleValue]; 55 | rightVal = [data[i] doubleValue]; 56 | dx = accuracy; 57 | } 58 | else 59 | { 60 | leftVal = [data[i-accuracy] doubleValue]; 61 | rightVal = [data[i+accuracy] doubleValue]; 62 | dx = accuracy * 2; 63 | } 64 | 65 | double dy = rightVal - leftVal; 66 | [derivative addObject:@(dy/dx)]; 67 | } 68 | 69 | return derivative; 70 | } 71 | 72 | NSArray *multiplyArrayByConstant(NSArray *data, double k) 73 | { 74 | NSMutableArray *output = [NSMutableArray arrayWithCapacity:data.count]; 75 | for(int i = 0; i < data.count; i++) 76 | { 77 | double val = [data[i] doubleValue]; 78 | [output addObject:@(val * k)]; 79 | } 80 | return output; 81 | } 82 | 83 | 84 | int getMinGap(NSArray *data) 85 | { 86 | int minGap = 1230123; 87 | int lastSigIndex = 0; 88 | 89 | for (int i = 0; i < data.count; i++) 90 | { 91 | if ([data[i] doubleValue] >= kProcessingSecondDerivCutoff) 92 | { 93 | if (lastSigIndex > 0) 94 | { 95 | int gap = i - lastSigIndex; 96 | if (gap < minGap) { 97 | minGap = gap; 98 | } 99 | } 100 | 101 | lastSigIndex = i; 102 | } 103 | } 104 | return minGap; 105 | } 106 | 107 | NSArray *cutoffData(NSArray *data, double cutoff) 108 | { 109 | NSMutableArray *output = [NSMutableArray arrayWithCapacity:data.count]; 110 | for(int i = 0; i < data.count; i++) 111 | { 112 | double value = [data[i] doubleValue]; 113 | if(fabs(value) < cutoff) 114 | { 115 | [output addObject:@NO]; 116 | } 117 | else 118 | { 119 | [output addObject:@YES]; 120 | } 121 | } 122 | return output; 123 | } 124 | 125 | NSArray *mergeGaps(NSArray *data, int maxWidth) 126 | { 127 | NSMutableArray *output = [data mutableCopy]; 128 | int distance = 0; 129 | for (int i = 0; i < output.count; i++) 130 | { 131 | BOOL value = [output[i] boolValue]; 132 | if(distance == 0 && value) 133 | { 134 | distance = maxWidth; 135 | } 136 | else if(distance > 0 && value) 137 | { 138 | int mergeAmount = maxWidth - distance; 139 | for(int j = i - mergeAmount; j < i; j++) 140 | { 141 | if(j < 0) continue; 142 | output[j] = @YES; 143 | } 144 | distance = maxWidth; 145 | } 146 | else if(!value) 147 | { 148 | distance--; 149 | distance = MAX(0, distance); 150 | } 151 | } 152 | 153 | return output; 154 | } 155 | 156 | NSArray *findMidpointsOfClumps(NSArray *data) 157 | { 158 | NSMutableArray *midpointIndices = [NSMutableArray array]; 159 | 160 | int clumpStart = -1; 161 | BOOL isInClump = NO; 162 | for (int i = 0; i < data.count; i++) 163 | { 164 | BOOL value = [data[i] boolValue]; 165 | if(value && !isInClump) 166 | { 167 | clumpStart = i; 168 | isInClump = YES; 169 | } 170 | else if(!value && isInClump) 171 | { 172 | int midpoint = (i - 1 + clumpStart) / 2; 173 | [midpointIndices addObject:@(midpoint)]; 174 | isInClump = NO; 175 | } 176 | } 177 | 178 | return midpointIndices; 179 | } 180 | 181 | NSArray *findDistances(NSArray *data) 182 | { 183 | if(data.count == 0 || data == nil) return nil; 184 | 185 | NSMutableArray *diffArray = [NSMutableArray arrayWithCapacity:data.count]; 186 | [diffArray addObject:data[0]]; 187 | for (int i = 0; i < data.count; i++) 188 | { 189 | if (i < data.count - 1) 190 | { 191 | int diff = [data[i + 1] intValue] - [data[i] intValue]; 192 | [diffArray addObject:@(diff)]; 193 | } 194 | } 195 | return diffArray; 196 | } 197 | 198 | NSArray *clumpData(NSArray *data, int tolerance) 199 | { 200 | NSMutableArray *clumps = [NSMutableArray array]; 201 | for (int i = 0; i < data.count; i++) 202 | { 203 | int number = [data[i] intValue]; 204 | double minDiff = DBL_MAX; 205 | Clump *minDiffClump = nil; 206 | for (int j = 0; j < clumps.count; j++) 207 | { 208 | double diff = fabs(number - [clumps[j] average]); 209 | if (diff < minDiff) 210 | { 211 | minDiff = diff; 212 | minDiffClump = clumps[j]; 213 | } 214 | } 215 | 216 | if (minDiff <= tolerance) 217 | { 218 | [minDiffClump addNumber:number]; 219 | } 220 | else 221 | { 222 | Clump *newClump = [[Clump alloc] init]; 223 | [newClump addNumber:number]; 224 | [clumps addObject:newClump]; 225 | } 226 | } 227 | 228 | return clumps; 229 | } 230 | void printArray(NSArray *data) 231 | { 232 | for (int i = 0; i < data.count; i++) 233 | { 234 | printf("%s,", [[data[i] description] UTF8String]); 235 | } 236 | printf("\n"); 237 | } 238 | 239 | -------------------------------------------------------------------------------- /Ultrasound/ProcessingFunctionsC.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingFunctionsC.c 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/10/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include "ProcessingFunctionsC.h" 12 | 13 | // Basic statistics 14 | double maxValueForArray(float *array, int start, int end) 15 | { 16 | // start = MAX(0, start); 17 | 18 | double maxValue = 0; 19 | for (int i = start; i <= end; i++) 20 | { 21 | double val = array[i]; 22 | if(val > maxValue) 23 | { 24 | maxValue = val; 25 | } 26 | } 27 | 28 | return maxValue; 29 | } 30 | 31 | double meanOfArray(float *array, int start, int end) 32 | { 33 | // start = MAX(0, start); 34 | 35 | double sum = 0; 36 | for (int i = start; i <= end; i++) { 37 | sum += array[i]; 38 | } 39 | return sum / (end - start + 1); 40 | } 41 | 42 | double standardDeviation(float *array, int start, int end, double mean) 43 | { 44 | // start = MAX(0, start); 45 | 46 | double totalDiff = 0.0; 47 | for (int i = start; i <= end; i++) 48 | { 49 | double diff = array[i] - mean; 50 | diff *= diff; 51 | totalDiff += diff; 52 | } 53 | 54 | float standardDeviation = sqrt((float)(totalDiff / (end - start + 1))); 55 | return standardDeviation; 56 | } 57 | 58 | double meanlessStandardDeviation(float *array, int start, int end) 59 | { 60 | return standardDeviation(array, start, end, meanOfArray(array, start, end)); 61 | } 62 | 63 | #define MIN(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; }) 64 | -------------------------------------------------------------------------------- /Ultrasound/ProcessingFunctionsC.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingFunctionsC.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/10/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #ifndef Ultrasound_ProcessingFunctionsC_h 10 | #define Ultrasound_ProcessingFunctionsC_h 11 | 12 | // Basic statistics 13 | double maxValueForArray(float *array, int start, int end); 14 | double meanOfArray(float *array, int start, int end); 15 | double standardDeviation(float *array, int start, int end, double mean); 16 | double meanlessStandardDeviation(float *array, int start, int end); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /Ultrasound/Processor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Processor.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/3/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Processor : NSObject 12 | 13 | + (NSArray *) processPacketData:(NSArray *)packetData; 14 | 15 | + (NSArray *) splitByteArrayIntoNibbleArray:(NSArray *)bytes; 16 | + (NSArray *) combineNibbleArrayToByteArray:(NSArray *)nibbles; 17 | 18 | 19 | // String encoding 20 | + (NSArray *) encodeString:(NSString *)string; 21 | + (NSArray *) encodeStringAndEncrypt:(NSString *)string withKey:(NSString *) key; 22 | + (NSString *) decodeDataAndDecrypt:(NSArray *)data withKey:(NSString *) key; 23 | + (NSString *) decodeData:(NSArray *)data; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Ultrasound/Processor.m: -------------------------------------------------------------------------------- 1 | // 2 | // Processor.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/3/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "Processor.h" 10 | #import "ProcessAlgoMain.h" 11 | #import "NSData+AES256.h" 12 | 13 | //#define kNumberLength 25.0 14 | 15 | @implementation Processor 16 | 17 | + (void) incrementCountForKey:(id)key inDictionary:(NSMutableDictionary *)dict 18 | { 19 | NSNumber *count = [dict objectForKey:key]; 20 | if(count) 21 | { 22 | [dict setObject:@(count.intValue + 1) forKey:key]; 23 | } 24 | else 25 | { 26 | [dict setObject:@(1) forKey:key]; 27 | } 28 | } 29 | 30 | 31 | + (NSArray *) processPacketData:(NSArray *) packetData 32 | { 33 | NSMutableArray *result = [NSMutableArray array]; 34 | NSArray *distanceSpacing = nil; 35 | double fallbackPacketLength = [ProcessAlgoMain getDistanceSpacingFallback:packetData andDistancesIntoArray:&distanceSpacing]; 36 | //int numSections = ceil(packetData.count / fallbackPacketLength); 37 | 38 | double increment = [distanceSpacing[0] doubleValue]; 39 | BOOL needToSync = NO; 40 | int syncCounter = 0; 41 | int distanceIndex = 0; 42 | 43 | double lastIncrement = 0; 44 | for (int i = 0; i < packetData.count; i += lastIncrement) 45 | { 46 | BOOL isFakeData = increment < fallbackPacketLength * 0.5; 47 | if (increment > fallbackPacketLength * 1.5) 48 | { 49 | syncCounter = round(increment / fallbackPacketLength); 50 | increment = increment / syncCounter; 51 | lastIncrement = increment; 52 | distanceIndex++; 53 | // needToSync = YES; 54 | } 55 | 56 | if(!isFakeData) 57 | { 58 | NSMutableArray *subData = [NSMutableArray array]; 59 | //printf("Start sub data: %i\nEnd sub data:%i\n", i, (int)(i + increment - 1)); 60 | for (int j = i; j < i + increment - 1; j++) 61 | { 62 | [subData addObject:packetData[j]]; 63 | } 64 | 65 | int mode = [self findModeForArray:subData]; 66 | [result addObject:@(mode)]; 67 | } 68 | 69 | if (syncCounter > 0) 70 | { 71 | syncCounter--; 72 | if (syncCounter == 0) 73 | { 74 | needToSync = YES; 75 | } 76 | } 77 | else 78 | { 79 | lastIncrement = increment; 80 | 81 | distanceIndex++; 82 | if(distanceIndex >= distanceSpacing.count) 83 | { 84 | break; 85 | } 86 | increment = [distanceSpacing[distanceIndex] doubleValue]; 87 | } 88 | 89 | if (needToSync) 90 | { 91 | if(distanceIndex >= distanceSpacing.count) 92 | { 93 | break; 94 | } 95 | 96 | NSLog(@"Sync"); 97 | 98 | int sum = 0; 99 | for (int j = 0; j < distanceIndex; j++) 100 | { 101 | sum += [distanceSpacing[j] intValue]; 102 | } 103 | 104 | i = sum - increment + 1; 105 | lastIncrement = increment; 106 | increment = [distanceSpacing[distanceIndex] intValue]; 107 | needToSync = NO; 108 | } 109 | } 110 | return [result copy]; 111 | } 112 | 113 | + (double) findMin: (NSArray *) array 114 | { 115 | NSArray *temp = [array copy]; 116 | temp = [temp sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { 117 | 118 | if ([obj2 intValue] > [obj1 intValue]) 119 | { 120 | return NSOrderedAscending; 121 | } 122 | else if([obj2 intValue] < [obj1 intValue]) 123 | { 124 | return NSOrderedDescending; 125 | } 126 | else 127 | { 128 | return NSOrderedSame; 129 | } 130 | }]; 131 | 132 | return [temp[0] doubleValue]; 133 | } 134 | 135 | + (int) findModeForArray: (NSArray *) array 136 | { 137 | NSMutableDictionary *dataSet = [NSMutableDictionary dictionary]; 138 | 139 | for (int i = 0; i < array.count; i++) 140 | { 141 | [self incrementCountForKey:array[i] inDictionary:dataSet]; 142 | } 143 | 144 | int maxCount = 0; 145 | int mode = 0; 146 | for(NSNumber *value in dataSet) 147 | { 148 | int count = [[dataSet objectForKey:value] intValue]; 149 | if(count > maxCount) 150 | { 151 | maxCount = count; 152 | mode = [value intValue]; 153 | } 154 | } 155 | 156 | return mode; 157 | } 158 | 159 | + (NSArray *) combineNibbleArrayToByteArray:(NSArray *)nibbles 160 | { 161 | if(nibbles.count % 2 == 1) 162 | { 163 | NSLog(@"Odd data length... returning nil!"); 164 | return nil; 165 | } 166 | 167 | NSMutableArray *bytes = [NSMutableArray arrayWithCapacity:nibbles.count / 2]; 168 | for(int i = 0; i < nibbles.count; i += 2) 169 | { 170 | int val0 = [nibbles[i+1] intValue]; 171 | int val1 = [nibbles[i] intValue]; 172 | int combined = val1 * 16 + val0; // 16 = 2^4 173 | [bytes addObject:@(combined)]; 174 | } 175 | 176 | return bytes; 177 | } 178 | 179 | + (NSArray *) splitByteArrayIntoNibbleArray:(NSArray *) bytes 180 | { 181 | NSMutableArray *output = [[NSMutableArray alloc] initWithCapacity:bytes.count * 2]; 182 | 183 | for (int i = 0; i < bytes.count; i++) 184 | { 185 | int val = [bytes[i] intValue]; 186 | int val1 = val / 16; 187 | int val2 = val - val1 * 16; 188 | [output addObject:@(val1)]; 189 | [output addObject:@(val2)]; 190 | } 191 | 192 | return output; 193 | } 194 | 195 | 196 | + (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key 197 | { 198 | return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key]; 199 | } 200 | 201 | // Fun debug encoding 202 | + (NSArray *) encodeStringAndEncrypt:(NSString *)string withKey:(NSString *) key 203 | { 204 | NSData *cipher = [self encryptString: string withKey: key]; 205 | NSUInteger len = [cipher length]; 206 | Byte *byteData = (Byte*) malloc(len); 207 | memcpy(byteData, [cipher bytes], len); 208 | 209 | NSMutableArray *bytes = [NSMutableArray arrayWithCapacity:string.length]; 210 | for (int i = 0; i < len; i++) 211 | { 212 | [bytes addObject:@(byteData[i])]; 213 | } 214 | 215 | free(byteData); 216 | 217 | return [self splitByteArrayIntoNibbleArray:bytes]; 218 | } 219 | 220 | + (NSArray *) encodeString:(NSString *)string 221 | { 222 | NSMutableArray *bytes = [NSMutableArray arrayWithCapacity:string.length]; 223 | for(int i = 0; i < string.length; i++) 224 | { 225 | unichar c = [string characterAtIndex:i]; 226 | [bytes addObject:@(c)]; 227 | } 228 | 229 | //return [self splitByteArrayIntoNibbleArray:bytes]; 230 | return bytes; 231 | } 232 | 233 | + (NSString *) decodeData:(NSArray *)data 234 | { 235 | // NSArray *bytes = [self combineNibbleArrayToByteArray:data]; 236 | NSArray *bytes = data; 237 | if(!bytes) return nil; 238 | 239 | NSMutableString *string = [NSMutableString string]; 240 | for(int i = 0; i < bytes.count; i++) 241 | { 242 | unichar c = [bytes[i] intValue]; 243 | [string appendFormat:@"%c", c]; 244 | } 245 | 246 | return [string copy]; 247 | } 248 | 249 | + (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key 250 | { 251 | return [[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding]; 252 | } 253 | 254 | + (NSString *) decodeDataAndDecrypt:(NSArray *)data withKey:(NSString *) key 255 | { 256 | NSArray *bytes = [self combineNibbleArrayToByteArray:data]; 257 | Byte *buffer = malloc(sizeof(Byte) * bytes.count); 258 | for (int i = 0; i < bytes.count; i++) 259 | { 260 | buffer[i] = [bytes[i] intValue]; 261 | } 262 | 263 | NSData *cipher = [NSData dataWithBytes:buffer length:bytes.count]; 264 | NSString *plainText = [self decryptData:cipher withKey:key]; 265 | free(buffer); 266 | 267 | return plainText; 268 | } 269 | 270 | @end 271 | -------------------------------------------------------------------------------- /Ultrasound/ReceiveViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ReceiveViewController.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/26/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AudioPlayer.h" 11 | #import "GraphView.h" 12 | 13 | @interface ReceiveViewController : UIViewController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Ultrasound/ReceiveViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ReceiveViewController.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/26/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "ReceiveViewController.h" 10 | #import "AudioManager.h" 11 | #import "UIView+Donald.h" 12 | #import "Processor.h" 13 | #import "NSArray+Levenshtein.h" 14 | 15 | @interface ReceiveViewController () 16 | @property (nonatomic, strong) AudioPlayer *player; 17 | @property (weak, nonatomic) IBOutlet UILabel *receivedStringLabel; 18 | @property (weak, nonatomic) IBOutlet GraphView *graphView; 19 | @property (nonatomic) float *copiedFFTData; 20 | @property (nonatomic) float copiedCutoff; 21 | @property (nonatomic) NSString *testString; 22 | @end 23 | 24 | @implementation ReceiveViewController 25 | 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | self.player = [AudioPlayer sharedAudioPlayer]; 32 | self.player.receiveDelegate = self; 33 | 34 | // [self.containerView applyStandardSinkStyle]; 35 | } 36 | 37 | - (void) viewDidAppear:(BOOL)animated 38 | { 39 | [super viewDidAppear:animated]; 40 | 41 | self.player.isReceiving = YES; 42 | [self.player start]; 43 | } 44 | 45 | - (void) viewWillDisappear:(BOOL)animated 46 | { 47 | [super viewWillDisappear:animated]; 48 | 49 | [self.player stop]; 50 | self.player.isReceiving = NO; 51 | } 52 | 53 | - (void) audioReceivedDataUpdate:(int)data 54 | { 55 | 56 | } 57 | 58 | - (void) audioReceivedText:(NSString *) text rollingAverage:(float)avg 59 | { 60 | if (text == nil) 61 | { 62 | self.receivedStringLabel.text = @"nil"; 63 | } 64 | else 65 | { 66 | self.receivedStringLabel.text = [NSString stringWithFormat:@"%@, avg = %f", text, avg]; 67 | // Nibbles we received 68 | // NSLog(@"Received: %@\n\nShould have received: %@", nibbles, correctNibbles); 69 | 70 | } 71 | } 72 | 73 | - (void) audioReceivedFFTData:(float *)data arraySize:(int)size cutoff:(float)cutoff 74 | { 75 | if(self.copiedFFTData != NULL) 76 | { 77 | free(self.copiedFFTData); 78 | } 79 | 80 | self.copiedFFTData = malloc(sizeof(float) * size); 81 | memcpy(self.copiedFFTData, data, sizeof(float) * size); 82 | 83 | self.copiedCutoff = cutoff; 84 | 85 | [self.graphView generateBitmapAndRedraw]; 86 | } 87 | 88 | 89 | 90 | #pragma mark - Graph Stuff 91 | 92 | - (void) setGraphView:(GraphView *)graphView 93 | { 94 | _graphView = graphView; 95 | _graphView.dataSource = self; 96 | 97 | [_graphView setupInitialTransforms]; 98 | 99 | [_graphView applyStandardSinkStyleNoRounding]; 100 | } 101 | 102 | - (double) valueForXCoord:(double)x withIndex:(int)graphIndex graphView:(GraphView *)view 103 | { 104 | if(graphIndex == 0) 105 | { 106 | if(self.copiedFFTData == NULL || x >= 22000) 107 | { 108 | return 0; 109 | } 110 | 111 | int index = round(x / kRatio); 112 | return self.copiedFFTData[index]; 113 | } 114 | else 115 | { 116 | return self.copiedCutoff; 117 | } 118 | } 119 | 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /Ultrasound/SpectrumAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rad2fft.h" 6 | #include "SpectrumAnalysis.h" 7 | 8 | #define Scale(e) powf(2.0,e) 9 | 10 | #define kLog2TableLog2Size 8 11 | #define kLog2TableSize (1<>shiftArg]; 66 | } 67 | return y; 68 | } 69 | 70 | 71 | #if defined __arm__ 72 | inline int mul32_16b(int32_t x, int32_t y) { int32_t z; asm volatile("smulwb %0, %1, %2" : "=r"(z) : "r"(x), "r"(y)); return z; } 73 | inline int mul32_16t(int32_t x, int32_t y) { int32_t z; asm volatile("smulwt %0, %1, %2" : "=r"(z) : "r"(x), "r"(y)); return z; } 74 | inline int32_t SquareMag(int32_t re, int32_t im) 75 | { 76 | register int32_t z; 77 | asm volatile("smultt %0, %1, %2" : "=r"(z) : "r"(re), "r"(re)); 78 | asm volatile("smlatt %0, %1, %2, %3" : "=r"(z) : "r"(im), "r"(im), "0"(z)); 79 | return z; 80 | } 81 | #else 82 | #define mul32_16b(a,b) ((int32_t)(((int64_t)(a) * (int64_t)((b) & 0x0000ffff))>>16)) 83 | #define mul32_16t(a,b) ((int32_t)(((int64_t)(a) * (int64_t)(((b) & 0xffff0000)>>16))>>16)) 84 | inline int32_t SquareMag(int32_t re, int32_t im) { return (re>>16)*(re>>16)+(im>>16)*(im>>16); } 85 | #endif 86 | 87 | 88 | struct SPECTRUM_ANALYSIS 89 | { 90 | int32_t size; 91 | int16_t* weightingWindow; 92 | Int32Cplx* fftBuffer; 93 | PackedInt16Cplx* twiddleFactors; 94 | }; 95 | 96 | 97 | 98 | H_SPECTRUM_ANALYSIS SpectrumAnalysisCreate(int32_t size) 99 | { 100 | H_SPECTRUM_ANALYSIS p = (SPECTRUM_ANALYSIS*)malloc(sizeof(SPECTRUM_ANALYSIS)); 101 | if(p) 102 | { 103 | p->size = size; 104 | 105 | p->weightingWindow = (int16_t*)malloc(sizeof(int16_t)*size); 106 | float nrg = 0.0f; 107 | for(int i = 0; i < size/2; ++i) 108 | { 109 | /* Hamming window */ 110 | float w = 0.53836-0.46164*cosf(2.0*M_PI*i/(float)(size-1)); 111 | nrg += 2.0*w*w; 112 | p->weightingWindow[i] = (int16_t)(powf(2.0, 15.0)*w); 113 | p->weightingWindow[size-i-1] = p->weightingWindow[i]; 114 | } 115 | 116 | p->fftBuffer = (Int32Cplx*)malloc(sizeof(Int32Cplx)*size); 117 | memset(p->fftBuffer, 0, sizeof(Int32Cplx)*size); 118 | 119 | p->twiddleFactors = CreatePackedTwiddleFactors(size); 120 | } 121 | return p; 122 | } 123 | 124 | void SpectrumAnalysisDestroy(H_SPECTRUM_ANALYSIS p) 125 | { 126 | if(p) 127 | { 128 | if(p->weightingWindow) free(p->weightingWindow); 129 | if(p->fftBuffer) free(p->fftBuffer); 130 | 131 | DisposePackedTwiddleFactors(p->twiddleFactors); 132 | 133 | free(p); 134 | } 135 | } 136 | 137 | void SpectrumAnalysisProcess(H_SPECTRUM_ANALYSIS p, const int32_t* inTimeSig, int32_t* outMagSpectrum, bool in_dB) 138 | { 139 | if(p) 140 | { 141 | // Apply weighting window 142 | for(uint i = 0; i < p->size; i += 2) 143 | { 144 | int32_t dualCoef = *((int32_t*)(p->weightingWindow + i)); 145 | p->fftBuffer[i].real = mul32_16b(inTimeSig[i] << 7, dualCoef) << 1; 146 | p->fftBuffer[i].imag = 0; 147 | p->fftBuffer[i+1].real = mul32_16t(inTimeSig[i+1] << 7, dualCoef) << 1; 148 | p->fftBuffer[i+1].imag = 0; 149 | } 150 | 151 | Radix2IntCplxFFT(p->fftBuffer, p->size, p->twiddleFactors, 1); 152 | 153 | if(in_dB) 154 | { 155 | // Calculate magnitude spectrum in dB 156 | for(uint i = 0; i < p->size/2; ++i) 157 | { 158 | // squared magnitude 159 | int32_t squaredMag = SquareMag(p->fftBuffer[i].real, p->fftBuffer[i].imag); 160 | 161 | // Avoid log(0) 162 | if(squaredMag) 163 | { 164 | // squared mag -> log2 165 | squaredMag = log2Int(squaredMag<<1) + kAdjust0dBLevel; 166 | } 167 | else 168 | { 169 | squaredMag = kAdjust0dBLevel; 170 | } 171 | 172 | // log2 -> 10*log10 conversion (Q5.26 x Q2.13) 173 | outMagSpectrum[i] = mul32_16b(squaredMag, kLog2ToLog10ScaleFactor) << 1; 174 | } 175 | } 176 | else 177 | { 178 | // Calculate squared magnitude spectrum 179 | for(uint i = 0; i < p->size / 2; ++i) 180 | { 181 | // squared magnitude 182 | outMagSpectrum[i] = SquareMag(p->fftBuffer[i].real, p->fftBuffer[i].imag); 183 | } 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /Ultrasound/SpectrumAnalysis.h: -------------------------------------------------------------------------------- 1 | #if !defined __SPECTRUM_ANALYSIS_H__ 2 | #define __SPECTRUM_ANALYSIS_H__ 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /* 11 | * Forward declarations 12 | */ 13 | struct SPECTRUM_ANALYSIS; 14 | typedef struct SPECTRUM_ANALYSIS* H_SPECTRUM_ANALYSIS; 15 | 16 | 17 | /* 18 | * Create a SpectrumAnalysis object. The block size argument must be a power of 2 19 | */ 20 | H_SPECTRUM_ANALYSIS SpectrumAnalysisCreate(int32_t blockSize); 21 | 22 | 23 | /* 24 | * Dispose SpectrumAnalysis object 25 | */ 26 | void SpectrumAnalysisDestroy(H_SPECTRUM_ANALYSIS p); 27 | 28 | /* 29 | * 30 | * Inputs: 31 | * p: an opaque SpectrumAnalysis object handle 32 | * inTimeSig: pointer to a time signal of the same length as specified in SpectrumAnalysisCreate() 33 | * outMagSpectrum: pointer to a magnitude spectrum. Its length must at least be size/2 34 | * in_dB: flag indicating wether the magnitude spectrum should be calculated in dB 35 | * 36 | * Discussion: 37 | * 38 | * the real valued time signal is first weighted with a Hamming window of the same size and then transformed 39 | * in the frequency domain. The squared magnitudes of the resulting complex spectrum are copied into the 40 | * outMagSpectrum vector and then converted to dB if so requested. Since the input signal is real, the magnitude 41 | * spectrum is only half the size (note that the Nyquist term is discarded) as the input signal. 42 | * 43 | * Value ranges: 44 | * 45 | * the input signal is expected to be in a Q7.24 format in the range [-1, 1) which means that the integer parts should be zero 46 | * the ouput magnitude spectrum is in Q7.24 format with a range of [-128, 0) when calculated in dB. 47 | */ 48 | void SpectrumAnalysisProcess(H_SPECTRUM_ANALYSIS p, const int32_t* inTimeSig, int32_t* outMagSpectrum, bool in_dB); 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /Ultrasound/Test Strings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | transmitString 6 | Test String 7 | repeatCount 8 | 20 9 | 10 | 11 | -------------------------------------------------------------------------------- /Ultrasound/Transforms.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef Calculator_Transforms_h 3 | #define Calculator_Transforms_h 4 | 5 | struct Transforms { 6 | CGPoint scale; // defined in pixels / coord 7 | CGPoint translation; // defined in Cartessian coords 8 | CGPoint center; // Center of the screen, in pixels 9 | }; typedef struct Transforms Transforms; 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /Ultrasound/TransmitGraphView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TransmitGraphView.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/29/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "GraphView.h" 10 | 11 | @interface TransmitGraphView : GraphView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Ultrasound/TransmitGraphView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TransmitGraphView.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/29/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "TransmitGraphView.h" 10 | 11 | @implementation TransmitGraphView 12 | 13 | - (Transforms) initialTransforms 14 | { 15 | Transforms trans = [super initialTransforms]; 16 | 17 | trans.translation.x = 0; 18 | trans.translation.y = 0; 19 | 20 | trans.scale.x = self.frame.size.width / (1.0 / 690); 21 | trans.scale.y = self.frame.size.height / 8; 22 | 23 | return trans; 24 | } 25 | 26 | - (CGPoint) tickMarkSpacing 27 | { 28 | return CGPointMake(10.0, 1.0); 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Ultrasound/TransmitViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TransmitViewController.h 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/26/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CardIO.h" 11 | #import "AudioPlayer.h" 12 | #import "GraphView.h" 13 | 14 | @interface TransmitViewController : UIViewController 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Ultrasound/TransmitViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TransmitViewController.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 7/26/13. 6 | // Copyright (c) 2013 AppDev. All rights reserved. 7 | // 8 | 9 | #import "TransmitViewController.h" 10 | #import "Processor.h" 11 | #import "UIView+Donald.h" 12 | #import "ProcessAlgoMain.h" 13 | #import "NSArray+Levenshtein.h" 14 | #import "iOS7ProgressView.h" 15 | #import 16 | #import 17 | 18 | @interface TransmitViewController () 19 | @property (nonatomic, strong) AudioPlayer *player; 20 | @property (weak, nonatomic) IBOutlet GraphView *graphView; 21 | @property (nonatomic) float *oldTransmittingFrequencies; 22 | @property (nonatomic) float *currentlyTransmittingFrequencies; 23 | @property (weak, nonatomic) IBOutlet UITextField *dataToTransmitField; 24 | @property (nonatomic, strong) NSTimer *phaseShiftTimer; 25 | @property (nonatomic) NSString *testString; 26 | @property (nonatomic) int testTransmissionIndex; 27 | @property (nonatomic) int repeatCount; 28 | 29 | @property (nonatomic, strong) UIPopoverController *cameraPopover; 30 | @property (nonatomic, weak) IBOutlet UILabel *transmissionLabel; 31 | @property (weak, nonatomic) IBOutlet iOS7ProgressView *progressBar; 32 | @end 33 | 34 | 35 | #define kCarrierWaveAttenuation 0.95 // 0.2 36 | @implementation TransmitViewController 37 | 38 | BOOL programChangesVolume = NO; 39 | - (void)viewDidLoad 40 | { 41 | [super viewDidLoad]; 42 | 43 | self.player = [AudioPlayer sharedAudioPlayer]; 44 | self.player.isReceiving = NO; 45 | self.player.transmitDelegate = self; 46 | 47 | NSString *path = [[NSBundle mainBundle] pathForResource:@"Test Strings" ofType:@"plist"]; 48 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; 49 | self.testString = dict[@"transmitString"]; 50 | self.repeatCount = [dict[@"repeatCount"] intValue]; 51 | 52 | NSLog(@"Test repeat count: %d", self.repeatCount); 53 | NSLog(@"Test nibbles: %@", [Processor encodeString:self.testString]); 54 | self.dataToTransmitField.text = self.testString; 55 | 56 | MPVolumeView *myVolumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(2000, 200, 400, 44)]; 57 | //[self.view addSubview:myVolumeView]; 58 | 59 | programChangesVolume = YES; 60 | [MPMusicPlayerController applicationMusicPlayer].volume = kCarrierWaveAttenuation; 61 | 62 | // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil]; 63 | self.progressBar.progressColor = [UIColor colorWithRed:0/255.0 green:122/255.0 blue:255/255.0 alpha:1.0]; 64 | self.progressBar.trackColor = [UIColor colorWithRed:184/255.0 green:184/255.0 blue:184/255.0 alpha:1.0]; 65 | [self.progressBar setProgress:0.0 animated:YES]; 66 | } 67 | 68 | 69 | 70 | - (void)volumeChanged:(NSNotification *)notification 71 | { 72 | if(programChangesVolume) 73 | { 74 | programChangesVolume = NO; 75 | } 76 | else 77 | { 78 | programChangesVolume = YES; 79 | [MPMusicPlayerController applicationMusicPlayer].volume = kCarrierWaveAttenuation; 80 | } 81 | } 82 | 83 | - (void) viewDidAppear:(BOOL)animated 84 | { 85 | [super viewDidAppear:animated]; 86 | 87 | self.player.isReceiving = NO; 88 | [self cameraPressed:nil]; 89 | 90 | } 91 | 92 | - (void) viewWillDisappear:(BOOL)animated 93 | { 94 | [super viewWillDisappear:animated]; 95 | 96 | [self.player stop]; 97 | self.player.isReceiving = YES; 98 | } 99 | 100 | - (void) audioFinishedTransmittingSequence 101 | { 102 | self.tabBarController.tabBar.userInteractionEnabled = YES; 103 | // self.tabBarController.tabBar.tintColor = self.view.tintColor; 104 | 105 | [self.phaseShiftTimer invalidate]; 106 | 107 | 108 | if(self.testTransmissionIndex < self.repeatCount - 1) 109 | { 110 | self.testTransmissionIndex++; 111 | [self.player transmitString:self.testString]; 112 | NSLog(@"Transmit count: %d", self.testTransmissionIndex); 113 | } 114 | else 115 | { 116 | self.testTransmissionIndex = 0; 117 | NSLog(@"Stopping transmission@"); 118 | [self.player stop]; 119 | 120 | NSString *soundPath = [[NSBundle mainBundle] pathForResource:@"ding" ofType:@"wav"]; 121 | SystemSoundID soundID; 122 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID); 123 | AudioServicesPlaySystemSound (soundID); 124 | } 125 | } 126 | - (void) audioStartedTransmittingSequence: (float *) freqs withSize: (int) size 127 | { 128 | self.tabBarController.tabBar.userInteractionEnabled = NO; 129 | self.tabBarController.tabBar.tintColor = [UIColor grayColor]; 130 | 131 | /*self.phaseShiftTimer = [NSTimer timerWithTimeInterval:0.0333 target:self selector:@selector(phaseShift:) userInfo:nil repeats:YES]; 132 | [[NSRunLoop mainRunLoop] addTimer:self.phaseShiftTimer forMode:NSRunLoopCommonModes]; 133 | [self.phaseShiftTimer fire];*/ 134 | } 135 | - (void) audioStartedTransmittingFrequencies:(float *)freqs withSize:(int)size 136 | { 137 | /*if(self.currentlyTransmittingFrequencies != NULL) 138 | { 139 | if(self.oldTransmittingFrequencies != NULL) 140 | { 141 | free(self.oldTransmittingFrequencies); 142 | } 143 | self.oldTransmittingFrequencies = malloc(sizeof(float) * size); 144 | 145 | memcpy(self.oldTransmittingFrequencies, self.currentlyTransmittingFrequencies, sizeof(float) * size); 146 | free(self.currentlyTransmittingFrequencies); 147 | } 148 | 149 | self.currentlyTransmittingFrequencies = malloc(sizeof(float) * size); 150 | memcpy(self.currentlyTransmittingFrequencies, freqs, sizeof(float) * size); 151 | [self.graphView generateBitmapAndRedraw]; 152 | 153 | justUpdated = YES;*/ 154 | } 155 | 156 | #pragma mark - Text Field Methods 157 | - (BOOL) textFieldShouldReturn:(UITextField *)textField 158 | { 159 | [textField endEditing:YES]; 160 | return YES; 161 | } 162 | 163 | - (BOOL) textFieldShouldEndEditing:(UITextField *)textField 164 | { 165 | return YES; 166 | } 167 | 168 | - (void) textFieldDidEndEditing:(UITextField *)textField 169 | { 170 | [self.player start]; 171 | [self.player transmitString:textField.text]; 172 | } 173 | 174 | 175 | #pragma mark - Card.io Methods 176 | - (IBAction)cameraPressed:(id)sender 177 | { 178 | CardIOPaymentViewController *scanViewController = [[CardIOPaymentViewController alloc] initWithPaymentDelegate:self]; 179 | scanViewController.appToken = @"0a3e3723bfde4ff683d03cd1520aabcc"; // get your app token from the card.io website 180 | //[self presentViewController:scanViewController animated:YES completion:nil]; 181 | 182 | self.cameraPopover = [[UIPopoverController alloc] initWithContentViewController:scanViewController]; 183 | self.cameraPopover.popoverContentSize = CGSizeMake(600, 600); 184 | 185 | CGRect popRect = self.progressBar.bounds; 186 | popRect.origin.y -= 50; 187 | [self.cameraPopover presentPopoverFromRect:popRect inView:self.progressBar permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 188 | 189 | /*[self addChildViewController:scanViewController]; 190 | [self.view addSubview:scanViewController.view]; 191 | scanViewController.view.frame = CGRectMake(20, 200, 400, 400);*/ 192 | } 193 | 194 | - (void) userDidCancelPaymentViewController:(CardIOPaymentViewController *)scanViewController 195 | { 196 | NSLog(@"User canceled payment info"); 197 | // Handle user cancellation here... 198 | [scanViewController dismissViewControllerAnimated:YES completion:nil]; 199 | } 200 | 201 | - (void) userDidProvideCreditCardInfo:(CardIOCreditCardInfo *)info inPaymentViewController:(CardIOPaymentViewController *)scanViewController 202 | { 203 | // The full card number is available as info.cardNumber, but don't log that! 204 | NSLog(@"Received card info. Number: %@, type:%i", info.cardNumber, info.cardType); 205 | // Use the card info... 206 | [scanViewController dismissViewControllerAnimated:YES completion:^{ 207 | self.dataToTransmitField.text = info.cardNumber; 208 | }]; 209 | } 210 | 211 | - (void) setGraphView:(GraphView *)graphView 212 | { 213 | _graphView = graphView; 214 | //_graphView.dataSource = self; 215 | 216 | [_graphView setupInitialTransforms]; 217 | _graphView.minRedrawInterval = 0.03; 218 | [_graphView applyStandardSinkStyleNoRounding]; 219 | } 220 | 221 | /*float t = 0; 222 | - (double) valueForXCoord:(double)x withIndex:(int)graphIndex graphView:(GraphView *)view 223 | { 224 | if (!self.oldTransmittingFrequencies || !self.currentlyTransmittingFrequencies) 225 | { 226 | return 0; 227 | } 228 | 229 | float timeSinceUpdate = CACurrentMediaTime() - lastUpdateT; 230 | float progress = MIN(timeSinceUpdate / kTransmitInterval, 1.0); 231 | double time = 2.0 * M_PI * (x + t); 232 | float sum = 0; 233 | for (int i = 0; i < kNumberOfTransmitFrequencies; i++) 234 | { 235 | float oldFreq = self.oldTransmittingFrequencies != NULL ? self.oldTransmittingFrequencies[i] : self.currentlyTransmittingFrequencies[i]; 236 | float newFreq = self.currentlyTransmittingFrequencies[i]; 237 | float val = sin(time * oldFreq) * (1 - progress) + sin(time * newFreq) * progress; 238 | 239 | sum += val; 240 | } 241 | 242 | return sum; 243 | }*/ 244 | 245 | /*float lastUpdateT = 0; 246 | BOOL justUpdated = NO; 247 | - (void) phaseShift:(NSTimer *)timer 248 | { 249 | t += 0.00001; 250 | 251 | if(justUpdated) 252 | { 253 | justUpdated = NO; 254 | lastUpdateT = CACurrentMediaTime(); 255 | } 256 | 257 | [self.graphView generateBitmapAndRedraw]; 258 | }*/ 259 | 260 | @end 261 | -------------------------------------------------------------------------------- /Ultrasound/UIView+Donald.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface UIView (Donald) 5 | 6 | - (UIImage *) imageSnapshot; 7 | 8 | - (void) applySinkStyleWithInnerColor:(UIColor *)innerColor borderColor:(UIColor *)borderColor borderWidth:(float)width andCornerRadius:(float)radius; 9 | - (void) applyStandardSinkStyle; 10 | - (void) applyStandardSinkStyleNoRounding; 11 | 12 | @end -------------------------------------------------------------------------------- /Ultrasound/UIView+Donald.m: -------------------------------------------------------------------------------- 1 | 2 | #import "UIView+Donald.h" 3 | #import 4 | 5 | @implementation UIView (Donald) 6 | 7 | - (UIImage *) imageSnapshot 8 | { 9 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0); 10 | [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 11 | 12 | UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 13 | 14 | UIGraphicsEndImageContext(); 15 | 16 | return img; 17 | } 18 | 19 | - (void) applySinkStyleWithInnerColor:(UIColor *)innerColor borderColor:(UIColor *)borderColor borderWidth:(float)width andCornerRadius:(float)radius 20 | { 21 | if(innerColor) self.backgroundColor = innerColor; 22 | if(borderColor) self.layer.borderColor = [borderColor CGColor]; 23 | 24 | self.layer.borderWidth = width; 25 | self.layer.cornerRadius = 10.0; 26 | } 27 | 28 | - (void) applyStandardSinkStyle 29 | { 30 | [self applySinkStyleWithInnerColor:nil borderColor:[UIColor colorWithWhite:227/255.0 alpha:1.0] borderWidth:1.0 andCornerRadius:10.0]; 31 | } 32 | 33 | - (void) applyStandardSinkStyleNoRounding 34 | { 35 | self.layer.borderColor = [[UIColor colorWithWhite:227/255.0 alpha:1.0] CGColor]; 36 | 37 | self.layer.borderWidth = 1.0; 38 | } 39 | 40 | @end -------------------------------------------------------------------------------- /Ultrasound/Ultrasound-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | appdev.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleURLTypes 24 | 25 | 26 | CFBundleTypeRole 27 | Viewer 28 | CFBundleURLName 29 | ultrasoundurl 30 | CFBundleURLSchemes 31 | 32 | ultra 33 | 34 | 35 | 36 | CFBundleVersion 37 | 1.0 38 | LSRequiresIPhoneOS 39 | 40 | UIMainStoryboardFile 41 | MainStoryboard_iPhone 42 | UIMainStoryboardFile~ipad 43 | MainStoryboard_iPad 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Ultrasound/Ultrasound-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Ultrasound' target in the 'Ultrasound' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Ultrasound/audio_helper.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "CAXException.h" 7 | #include "CAStreamBasicDescription.h" 8 | #include "audio_helper.h" 9 | 10 | // This determines how slowly the oscilloscope lines fade away from the display. 11 | // Larger numbers = slower fade (and more strain on the graphics processing) 12 | SInt8 *drawBuffers[kNumDrawBuffers]; 13 | 14 | int drawBufferIdx = 0; 15 | int drawBufferLen = kDefaultDrawSamples; 16 | int drawBufferLen_alloced = 0; 17 | 18 | /* 19 | int SetupRemoteIO (AudioUnit& inRemoteIOUnit, AURenderCallbackStruct inRenderProc) 20 | { 21 | try { 22 | // Open the output unit 23 | AudioComponentDescription desc; 24 | desc.componentType = kAudioUnitType_Output; 25 | desc.componentSubType = kAudioUnitSubType_RemoteIO; 26 | desc.componentManufacturer = kAudioUnitManufacturer_Apple; 27 | desc.componentFlags = 0; 28 | desc.componentFlagsMask = 0; 29 | 30 | AudioComponent comp = AudioComponentFindNext(NULL, &desc); 31 | 32 | AudioComponentInstanceNew(comp, &inRemoteIOUnit); 33 | 34 | UInt32 one = 1; 35 | AudioUnitSetProperty(inRemoteIOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one)); 36 | 37 | AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &inRenderProc, sizeof(inRenderProc)); 38 | 39 | // set our required format - Canonical AU format: LPCM non-interleaved 8.24 fixed point 40 | outFormat.SetAUCanonical(2, false); 41 | outFormat.mSampleRate = 44100; 42 | XThrowIfError(AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outFormat, sizeof(outFormat)), "couldn't set the remote I/O unit's output client format"); 43 | XThrowIfError(AudioUnitSetProperty(inRemoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outFormat, sizeof(outFormat)), "couldn't set the remote I/O unit's input client format"); 44 | 45 | AudioUnitInitialize(inRemoteIOUnit); 46 | } 47 | catch (CAXException &e) { 48 | char buf[256]; 49 | fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf)); 50 | return 1; 51 | } 52 | catch (...) { 53 | fprintf(stderr, "An unknown error occurred\n"); 54 | return 1; 55 | } 56 | 57 | return 0; 58 | } 59 | */ 60 | /*void SilenceData(AudioBufferList *inData) 61 | { 62 | for (UInt32 i=0; i < inData->mNumberBuffers; i++) 63 | memset(inData->mBuffers[i].mData, 0, inData->mBuffers[i].mDataByteSize); 64 | }*/ 65 | 66 | 67 | inline SInt32 smul32by16(SInt32 i32, SInt16 i16) 68 | { 69 | #if defined __arm__ 70 | register SInt32 r; 71 | asm volatile("smulwb %0, %1, %2" : "=r"(r) : "r"(i32), "r"(i16)); 72 | return r; 73 | #else 74 | return (SInt32)(((SInt64)i32 * (SInt64)i16) >> 16); 75 | #endif 76 | } 77 | 78 | inline SInt32 smulAdd32by16(SInt32 i32, SInt16 i16, SInt32 acc) 79 | { 80 | #if defined __arm__ 81 | register SInt32 r; 82 | asm volatile("smlawb %0, %1, %2, %3" : "=r"(r) : "r"(i32), "r"(i16), "r"(acc)); 83 | return r; 84 | #else 85 | return ((SInt32)(((SInt64)i32 * (SInt64)i16) >> 16) + acc); 86 | #endif 87 | } 88 | 89 | const Float32 DCRejectionFilter::kDefaultPoleDist = 0.975f; 90 | 91 | DCRejectionFilter::DCRejectionFilter(Float32 poleDist) 92 | { 93 | mA1 = (SInt16)((float)(1<<15)*poleDist); 94 | mGain = (mA1 >> 1) + (1<<14); // Normalization factor: (r+1)/2 = r/2 + 0.5 95 | Reset(); 96 | } 97 | 98 | void DCRejectionFilter::Reset() 99 | { 100 | mY1 = mX1 = 0; 101 | } 102 | 103 | void DCRejectionFilter::InplaceFilter(SInt32* ioData, UInt32 numFrames, UInt32 strides) 104 | { 105 | register SInt32 y1 = mY1, x1 = mX1; 106 | for (UInt32 i=0; i < numFrames; i++) 107 | { 108 | register SInt32 x0, y0; 109 | x0 = ioData[i*strides]; 110 | y0 = smul32by16(y1, mA1); 111 | y1 = smulAdd32by16(x0 - x1, mGain, y0) << 1; 112 | ioData[i*strides] = y1; 113 | x1 = x0; 114 | } 115 | mY1 = y1; 116 | mX1 = x1; 117 | } 118 | -------------------------------------------------------------------------------- /Ultrasound/audio_helper.h: -------------------------------------------------------------------------------- 1 | 2 | #if !defined(__rio_helper_h__) 3 | #define __rio_helper_h__ 4 | 5 | #include "CAStreamBasicDescription.h" 6 | 7 | #define kNumDrawBuffers 12 8 | #define kDefaultDrawSamples 1024 9 | #define kMinDrawSamples 64 10 | #define kMaxDrawSamples 4096 11 | 12 | extern int drawBufferIdx; 13 | extern int drawBufferLen; 14 | extern int drawBufferLen_alloced; 15 | extern SInt8 *drawBuffers[]; 16 | 17 | //int SetupRemoteIO (AudioUnit& inRemoteIOUnit, AURenderCallbackStruct inRenderProc); 18 | //void SilenceData(AudioBufferList *inData); 19 | 20 | class DCRejectionFilter 21 | { 22 | public: 23 | DCRejectionFilter(Float32 poleDist = DCRejectionFilter::kDefaultPoleDist); 24 | 25 | void InplaceFilter(SInt32* ioData, UInt32 numFrames, UInt32 strides); 26 | void Reset(); 27 | 28 | protected: 29 | 30 | // Coefficients 31 | SInt16 mA1; 32 | SInt16 mGain; 33 | 34 | // State variables 35 | SInt32 mY1; 36 | SInt32 mX1; 37 | 38 | static const Float32 kDefaultPoleDist; 39 | }; 40 | 41 | #endif -------------------------------------------------------------------------------- /Ultrasound/ding.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davisappdev/libultrasound-ios/f0d669354a984d9b769cf6818dadb6e6eaaaba56/Ultrasound/ding.wav -------------------------------------------------------------------------------- /Ultrasound/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Ultrasound/en.lproj/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 37 | 49 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 150 | 159 | 160 | 161 | 162 | 163 | 164 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /Ultrasound/en.lproj/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 60 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 133 | 142 | 147 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /Ultrasound/iOS7ProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // iOS7ProgressView.h 3 | // Protobowl 4 | // 5 | // Created by Donald Pinckney on 6/17/13. 6 | // Copyright (c) 2013 Donald Pinckney. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iOS7ProgressView : UIView 12 | 13 | @property (nonatomic) float progress; 14 | @property (nonatomic, strong) UIColor *trackColor; 15 | @property (nonatomic, strong) UIColor *progressColor; 16 | - (void) setProgress:(float)progress animated:(BOOL)animated; 17 | @end -------------------------------------------------------------------------------- /Ultrasound/iOS7ProgressView.m: -------------------------------------------------------------------------------- 1 | 2 | #import "iOS7ProgressView.h" 3 | 4 | @interface iOS7ProgressView () 5 | @property (nonatomic, strong) UIView *progressView; 6 | @property (nonatomic, strong) NSLayoutConstraint *progressWidthConstraint; 7 | 8 | @end 9 | 10 | @implementation iOS7ProgressView 11 | 12 | - (void) initLayout 13 | { 14 | self.backgroundColor = self.trackColor; 15 | 16 | self.progressView = [[UIView alloc] init]; 17 | self.progressView.translatesAutoresizingMaskIntoConstraints = NO; 18 | 19 | [self addSubview:self.progressView]; 20 | 21 | // Setup the progress view to take up the whole view vertically 22 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[progressView]-(0)-|" options:0 metrics:nil views:@{@"progressView" : self.progressView}]]; 23 | 24 | // Setup left constaint to always be 0, and the width to initially be 0, and later be resized 25 | NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.progressView attribute:NSLayoutAttributeLeft multiplier:1 constant:0]; 26 | self.progressWidthConstraint = [NSLayoutConstraint constraintWithItem:self.progressView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:0]; 27 | 28 | [self addConstraint:leftConstraint]; 29 | [self addConstraint:self.progressWidthConstraint]; 30 | } 31 | 32 | - (id)initWithFrame:(CGRect)frame 33 | { 34 | self = [super initWithFrame:frame]; 35 | if (self) { 36 | [self initLayout]; 37 | } 38 | return self; 39 | } 40 | 41 | - (id) initWithCoder:(NSCoder *)aDecoder 42 | { 43 | self = [super initWithCoder:aDecoder]; 44 | if(self) 45 | { 46 | [self initLayout]; 47 | } 48 | return self; 49 | } 50 | 51 | 52 | - (void) setProgressColor:(UIColor *)progressColor 53 | { 54 | self.progressView.backgroundColor = progressColor; 55 | } 56 | 57 | - (void) setTrackColor:(UIColor *)trackColor 58 | { 59 | self.backgroundColor = trackColor; 60 | } 61 | 62 | - (void) setProgress:(float)progress 63 | { 64 | [self setProgress:progress animated:NO]; 65 | } 66 | 67 | #define kAnimSpeed 200.0 // In units of pts / sec 68 | - (void) setProgress:(float)progress animated:(BOOL)animated 69 | { 70 | float toWidth = self.frame.size.width * progress; 71 | 72 | if(animated) 73 | { 74 | float oldWidth = self.progressWidthConstraint.constant; 75 | 76 | self.progressWidthConstraint.constant = toWidth; 77 | 78 | float dw = ABS(toWidth - oldWidth); 79 | // dw / dt = kAnimSpeed (constant) 80 | float dt = dw / kAnimSpeed; // (multiply with those differentials!) 81 | 82 | [UIView animateWithDuration:dt animations:^{ 83 | [self setNeedsLayout]; 84 | }]; 85 | } 86 | else 87 | { 88 | self.progressWidthConstraint.constant = toWidth; 89 | [self setNeedsLayout]; 90 | } 91 | } 92 | 93 | 94 | @end -------------------------------------------------------------------------------- /Ultrasound/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Ultrasound 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | 14 | 15 | // clean the console output. 16 | 17 | typedef int (*PYStdWriter)(void *, const char *, int); 18 | 19 | static PYStdWriter _oldStdWrite; 20 | 21 | 22 | 23 | int __pyStderrWrite(void *inFD, const char *buffer, int size) 24 | { 25 | if ( strncmp(buffer, "AssertMacros:", 13) == 0 ) { 26 | return 0; 27 | } 28 | return _oldStdWrite(inFD, buffer, size); 29 | } 30 | 31 | void __iOS7B5CleanConsoleOutput(void) 32 | { 33 | _oldStdWrite = stderr->_write; 34 | stderr->_write = __pyStderrWrite; 35 | } 36 | 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | __iOS7B5CleanConsoleOutput(); 41 | @autoreleasepool { 42 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Ultrasound/rad2fft.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rad2fft.h" 4 | 5 | #define CplxMul32Packed(x,p) { \ 6 | int tmp = x.real; int c = (p) & 0xffff0000; int s = ((p)<<16); \ 7 | x.real = (int)( ( (int64_t)tmp * (int64_t)c - (int64_t)x.imag * (int64_t)s ) >> 32 ); \ 8 | x.imag = (int)( ( (int64_t)tmp * (int64_t)s + (int64_t)x.imag * (int64_t)c ) >> 32 ); \ 9 | } \ 10 | 11 | #define Radix2IntButterfly(x0,x1,n) { \ 12 | int tmp = x0.real>>1; \ 13 | x0.real = tmp + (x1.real>>n);\ 14 | x1.real = tmp - (x1.real>>n);\ 15 | tmp = (x0.imag>>1); \ 16 | x0.imag = tmp + (x1.imag>>n);\ 17 | x1.imag = tmp - (x1.imag>>n);\ 18 | } \ 19 | 20 | static int FloatToInt16(float x) 21 | { 22 | int y; 23 | if(x<0.f) { 24 | if(x<=-32768.0f) y = -32768; 25 | else y = (int)(x - 0.5f); 26 | } else { 27 | if(x>=32767.0f) y = 32767; 28 | else y = (int)(x + 0.5f); 29 | } 30 | return y; 31 | } 32 | 33 | 34 | static void BitReverseReorder(Int32Cplx* ioCplxData, int N) 35 | { 36 | int linearIdx, bitReversedIdx; 37 | 38 | for(linearIdx = 1, bitReversedIdx = 0; linearIdx < N - 1; ++linearIdx) { 39 | int halfSize = N; 40 | do { 41 | halfSize >>=1; 42 | bitReversedIdx ^= halfSize; 43 | } while(bitReversedIdx < halfSize); 44 | 45 | if(linearIdx < bitReversedIdx) { 46 | /* Swap linear and bit reversed indexed values */ 47 | Int32Cplx tmp = ioCplxData[bitReversedIdx]; 48 | ioCplxData[bitReversedIdx] = ioCplxData[linearIdx]; 49 | ioCplxData[linearIdx] = tmp; 50 | } 51 | } 52 | } 53 | 54 | 55 | PackedInt16Cplx* CreatePackedTwiddleFactors(int size) 56 | { 57 | int i; 58 | PackedInt16Cplx* twiddleFactors = (PackedInt16Cplx*)malloc(sizeof(PackedInt16Cplx)*size); 59 | float scaleFac = (float)(1<<15); 60 | 61 | if(twiddleFactors) { 62 | for(i = 0; i < size/2; ++i) { 63 | int cosSin; 64 | float tmp; 65 | tmp = scaleFac*cosf(2.0*M_PI*i/size); 66 | cosSin = FloatToInt16(tmp) << 16; 67 | tmp = -scaleFac*sinf(2.0*M_PI*i/size); 68 | cosSin |= FloatToInt16(tmp) & 0x0000ffff; 69 | twiddleFactors[i] = cosSin; 70 | } 71 | } 72 | return twiddleFactors; 73 | } 74 | 75 | 76 | void DisposePackedTwiddleFactors(PackedInt16Cplx* twiddleFactors) 77 | { 78 | if(twiddleFactors) { 79 | free(twiddleFactors); 80 | } 81 | } 82 | 83 | 84 | void Radix2IntCplxFFT(Int32Cplx* ioCplxData, int size, const PackedInt16Cplx* twiddleFactors, int twiddleFactorsStrides) 85 | { 86 | int span, twiddle, strides; 87 | 88 | /* Reorder input data in bit reversed order */ 89 | BitReverseReorder(ioCplxData, size); 90 | 91 | span = 1; 92 | twiddle = 1; 93 | strides = twiddleFactorsStrides*size / 2; 94 | 95 | do { 96 | Int32Cplx x0, x1; 97 | int idx = 0; 98 | 99 | do { 100 | /* Multiply-less butterfly */ 101 | x1 = ioCplxData[idx+span]; 102 | x0 = ioCplxData[idx]; 103 | Radix2IntButterfly(x0, x1, 1); 104 | ioCplxData[idx] = x0; 105 | ioCplxData[idx+span] = x1; 106 | idx += span << 1; 107 | } while(idx < size); 108 | 109 | twiddle = 1; 110 | 111 | while(twiddle < span) { 112 | int packedTwiddleFactor = twiddleFactors[strides*twiddle]; 113 | idx = twiddle; 114 | 115 | do { 116 | x1 = ioCplxData[idx+span]; 117 | x0 = ioCplxData[idx]; 118 | CplxMul32Packed(x1, packedTwiddleFactor); 119 | Radix2IntButterfly(x0, x1, 0); 120 | ioCplxData[idx] = x0; 121 | ioCplxData[idx+span] = x1; 122 | idx += span << 1; 123 | } while(idx < size); 124 | ++twiddle; 125 | } 126 | span <<= 1; 127 | strides >>= 1; 128 | } while(span < size); 129 | } 130 | -------------------------------------------------------------------------------- /Ultrasound/rad2fft.h: -------------------------------------------------------------------------------- 1 | #ifndef __RAD2_FFT_H__ 2 | #define __RAD2_FFT_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* 9 | * Struct for holding a 32 bit integer complex numbers 10 | */ 11 | struct Int32Cplx 12 | { 13 | int real; 14 | int imag; 15 | }; 16 | typedef struct Int32Cplx Int32Cplx; 17 | 18 | /* 19 | * Packed complex type. The upper 16 bits correspond to the real part, 20 | * the lower 16 bit to imaginary part 21 | */ 22 | typedef int PackedInt16Cplx; 23 | 24 | 25 | /* 26 | * Create a lookup table with "size" twiddle factors for the FFT. 27 | */ 28 | PackedInt16Cplx* CreatePackedTwiddleFactors(int size); 29 | 30 | 31 | /* 32 | * Dispose the twiddle factor table 33 | */ 34 | void DisposePackedTwiddleFactors(PackedInt16Cplx* cosSinTable); 35 | 36 | 37 | /* 38 | * Inplace complex radix 2 FFT. The complex data vector must have the specified size and must be a power of 2. 39 | */ 40 | void Radix2IntCplxFFT(Int32Cplx* ioCplxData, int size, const PackedInt16Cplx* twiddleFactors, int twiddleFactorsStrides); 41 | 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /UltrasoundTests/UltrasoundTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | appdev.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /UltrasoundTests/UltrasoundTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // UltrasoundTests.h 3 | // UltrasoundTests 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UltrasoundTests : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /UltrasoundTests/UltrasoundTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // UltrasoundTests.m 3 | // UltrasoundTests 4 | // 5 | // Created by AppDev on 9/28/12. 6 | // Copyright (c) 2012 AppDev. All rights reserved. 7 | // 8 | 9 | #import "UltrasoundTests.h" 10 | #import "Processor.h" 11 | #include "ProcessingFunctionsC.h" 12 | #import "NSArray+Levenshtein.h" 13 | 14 | @implementation UltrasoundTests 15 | 16 | - (void)setUp 17 | { 18 | [super setUp]; 19 | } 20 | 21 | - (void)tearDown 22 | { 23 | [super tearDown]; 24 | } 25 | 26 | #pragma mark - Helper Methods 27 | - (NSArray *) getRandomBytes 28 | { 29 | int len = (rand() % 10000) + 1; 30 | NSMutableArray *bytes = [NSMutableArray arrayWithCapacity:len]; 31 | for(int i = 0; i < len; i++) 32 | { 33 | [bytes addObject:@(rand() % 100)]; 34 | } 35 | return bytes; 36 | } 37 | 38 | #pragma mark - Test Cases 39 | - (void) testStringEncoding 40 | { 41 | NSString *string = @"Marry had a little lab"; 42 | NSArray *data = [Processor encodeString:string]; 43 | NSString *result = [Processor decodeData:data]; 44 | 45 | STAssertEqualObjects(string, result, @"Original string and encoded then decoded string should be equal"); 46 | } 47 | 48 | - (void) testNibblesToBytes 49 | { 50 | for(int i = 0; i < 10; i++) 51 | { 52 | NSArray *originalBytes = [self getRandomBytes]; 53 | NSArray *nibbles = [Processor splitByteArrayIntoNibbleArray:originalBytes]; 54 | NSArray *newBytes = [Processor combineNibbleArrayToByteArray:nibbles]; 55 | STAssertEqualObjects(originalBytes, newBytes, @"Stuff is not equal"); 56 | } 57 | } 58 | 59 | - (void) testEncryption 60 | { 61 | NSString *plainText = @"Hello, world"; 62 | NSString *key = @"asdfsdfadf"; 63 | NSArray *encryptedData = [Processor encodeStringAndEncrypt:plainText withKey:key]; 64 | NSString *plainData = [Processor decodeDataAndDecrypt:encryptedData withKey:key]; 65 | STAssertEqualObjects(plainText, plainData, @"Encrypted and decrypted strings are not the same"); 66 | } 67 | 68 | - (void) testPercentError 69 | { 70 | NSArray *correct = @[@5, @9, @8, @2, @3, @9]; 71 | NSArray *received = @[@5, @8, @2, @2, @3, @9, @3, @2]; 72 | double error = [correct percentErrorToReceivedArray:received]; 73 | 74 | STAssertEqualsWithAccuracy(error, 4.0/6.0, 0.001, @"The error should equal 4/6, 0.6666"); 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /UltrasoundTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | --------------------------------------------------------------------------------