├── .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 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
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 |
61 |
62 |
63 |
64 |
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 |
143 |
144 |
145 |
146 |
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 |
--------------------------------------------------------------------------------