Joshua Moerman
11 years ago
8 changed files with 222 additions and 48 deletions
@ -0,0 +1,24 @@ |
|||||
|
//
|
||||
|
// Ruler.h
|
||||
|
// SpectogramPrototype
|
||||
|
//
|
||||
|
// Created by Joshua Moerman on 25/02/14.
|
||||
|
// Copyright (c) 2014 Joshua Moerman. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#import <UIKit/UIKit.h> |
||||
|
|
||||
|
typedef struct Interval { |
||||
|
CGFloat begin; |
||||
|
CGFloat end; |
||||
|
} Interval; |
||||
|
|
||||
|
@interface AbstractRuler : UIView |
||||
|
@property (nonatomic) Interval visibleInterval; |
||||
|
@end |
||||
|
|
||||
|
@interface HorizontalRuler : AbstractRuler |
||||
|
@end |
||||
|
|
||||
|
@interface VerticalRuler : AbstractRuler |
||||
|
@end |
@ -0,0 +1,114 @@ |
|||||
|
// |
||||
|
// Ruler.m |
||||
|
// SpectogramPrototype |
||||
|
// |
||||
|
// Created by Joshua Moerman on 25/02/14. |
||||
|
// Copyright (c) 2014 Joshua Moerman. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import "Ruler.h" |
||||
|
#import "UIScreen+Util.h" |
||||
|
|
||||
|
|
||||
|
@implementation AbstractRuler |
||||
|
@synthesize visibleInterval; |
||||
|
|
||||
|
- (void)setVisibleInterval:(Interval)visible_interval_{ |
||||
|
if (visibleInterval.begin != visible_interval_.begin || visibleInterval.end != visible_interval_.end) { |
||||
|
[self setNeedsDisplay]; |
||||
|
visibleInterval = visible_interval_; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
|
||||
|
@implementation HorizontalRuler |
||||
|
|
||||
|
- (void)drawRect:(CGRect) __unused rect{ |
||||
|
[[UIColor grayColor] setFill]; |
||||
|
UIRectFill(self.bounds); |
||||
|
|
||||
|
const Interval visibleInterval = self.visibleInterval; |
||||
|
if(visibleInterval.end <= visibleInterval.begin) return; |
||||
|
|
||||
|
const CGFloat f = 60 * 44100.0 / 4096.0; |
||||
|
const CGFloat start = f * ceil(visibleInterval.begin / f); |
||||
|
const CGFloat d = visibleInterval.end - visibleInterval.begin; |
||||
|
const int n = (int)floor(d / f) + 1; |
||||
|
|
||||
|
for(int i = 0; i < n; ++i){ |
||||
|
const CGFloat x = start + i * f; |
||||
|
const CGFloat r = (x - visibleInterval.begin) / d; |
||||
|
const CGFloat gx = r * self.bounds.size.width; |
||||
|
|
||||
|
[[UIColor blackColor] setFill]; |
||||
|
if([UIScreen isRetinaDisplay]){ |
||||
|
UIRectFill(CGRectMake(gx, 0, 0.5, self.bounds.size.height)); |
||||
|
} else { |
||||
|
UIRectFill(CGRectMake(gx, 0, 1.0, self.bounds.size.height)); |
||||
|
} |
||||
|
|
||||
|
NSString* string = [NSString stringWithFormat:@"%.0f:00", x/f]; |
||||
|
NSMutableParagraphStyle* style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; |
||||
|
style.alignment = NSTextAlignmentCenter; |
||||
|
UIFont* font = [UIFont boldSystemFontOfSize:14]; |
||||
|
[string drawInRect:CGRectMake(gx-50, 20, 100, self.bounds.size.height-20) |
||||
|
withAttributes:@{NSParagraphStyleAttributeName: style, |
||||
|
NSFontAttributeName: font}]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
|
||||
|
@implementation VerticalRuler |
||||
|
|
||||
|
- (UIColor*)colorForKey:(int)j{ |
||||
|
switch (j) { |
||||
|
case 0: |
||||
|
return [UIColor redColor]; |
||||
|
case 2: |
||||
|
case 3: |
||||
|
case 5: |
||||
|
case 7: |
||||
|
case 8: |
||||
|
case 10: |
||||
|
return [UIColor whiteColor]; |
||||
|
|
||||
|
default: |
||||
|
return [UIColor blackColor]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
- (void)drawRect:(CGRect) __unused rect{ |
||||
|
[[UIColor grayColor] setFill]; |
||||
|
UIRectFill(self.bounds); |
||||
|
|
||||
|
const Interval visibleInterval = self.visibleInterval; |
||||
|
if(visibleInterval.end <= visibleInterval.begin) return; |
||||
|
|
||||
|
const CGFloat d = visibleInterval.end - visibleInterval.begin; |
||||
|
const CGFloat f = 44100; |
||||
|
const CGFloat N = 1 << 12; |
||||
|
const CGFloat height = (1 << 12) >> 3; |
||||
|
|
||||
|
for(int i = 220; i < 44100/8; i *= 2){ |
||||
|
for(int j = 0; j < 12; ++j){ |
||||
|
const CGFloat k = i * pow(2, j/12.0); |
||||
|
const CGFloat y = N*k/f; |
||||
|
const CGFloat y2 = (height - y); |
||||
|
const CGFloat gy = 1024 * (y2 - visibleInterval.begin) / d; |
||||
|
|
||||
|
[[self colorForKey:j] setFill]; |
||||
|
|
||||
|
if([UIScreen isRetinaDisplay]){ |
||||
|
UIRectFill(CGRectMake(0, gy-0.5, self.bounds.size.width, 1.0)); |
||||
|
} else { |
||||
|
UIRectFill(CGRectMake(0, gy-1, self.bounds.size.width, 2.0)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@end |
@ -0,0 +1,15 @@ |
|||||
|
//
|
||||
|
// UIScreen+Util.h
|
||||
|
// SpectogramPrototype
|
||||
|
//
|
||||
|
// Created by Joshua Moerman on 25/02/14.
|
||||
|
// Copyright (c) 2014 Joshua Moerman. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#import <UIKit/UIKit.h> |
||||
|
|
||||
|
@interface UIScreen (Util) |
||||
|
|
||||
|
+ (BOOL) isRetinaDisplay; |
||||
|
|
||||
|
@end |
@ -0,0 +1,27 @@ |
|||||
|
// |
||||
|
// UIScreen+Util.m |
||||
|
// SpectogramPrototype |
||||
|
// |
||||
|
// Created by Joshua Moerman on 25/02/14. |
||||
|
// Copyright (c) 2014 Joshua Moerman. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import "UIScreen+Util.h" |
||||
|
|
||||
|
@implementation UIScreen (Util) |
||||
|
|
||||
|
// from http://stackoverflow.com/questions/3504173/detect-retina-display |
||||
|
+ (BOOL) isRetinaDisplay { |
||||
|
static BOOL retina = NO; |
||||
|
static BOOL alreadyChecked = NO; |
||||
|
if (!alreadyChecked) { |
||||
|
UIScreen *mainScreen = self.mainScreen; |
||||
|
if (mainScreen) { |
||||
|
retina = mainScreen.scale > 1.0; |
||||
|
alreadyChecked = YES; |
||||
|
} |
||||
|
} |
||||
|
return retina; |
||||
|
} |
||||
|
|
||||
|
@end |
Reference in new issue