Skip to content

Commit

Permalink
Merge pull request #39 from glaurent/YINalgorithm
Browse files Browse the repository at this point in the history
YIN algorithm, conversion of GuitarTuner example to Swift 3
  • Loading branch information
vadymmarkov committed Oct 23, 2016
2 parents 2125c4e + d89f9cb commit 0192a7d
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 57 deletions.
16 changes: 15 additions & 1 deletion Beethoven.xcodeproj/project.pbxproj
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
AF3190521DABE01600C897CA /* YINTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF3190511DABE01600C897CA /* YINTransformer.swift */; };
AF4AFD9A1DAA3462002B6DC9 /* YINUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4AFD991DAA3462002B6DC9 /* YINUtil.swift */; };
AFFF3FF11DB633B4004AD9D9 /* YINEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFFF3FF01DB633B4004AD9D9 /* YINEstimator.swift */; };
D51575B61C343B77006F8E75 /* Beethoven.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D51575AB1C343B77006F8E75 /* Beethoven.framework */; };
D59CB1571C345E0A00290B63 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59CB1371C345E0A00290B63 /* Config.swift */; };
D59CB1581C345E0A00290B63 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59CB1391C345E0A00290B63 /* Buffer.swift */; };
Expand Down Expand Up @@ -55,12 +58,15 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
AF3190511DABE01600C897CA /* YINTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = YINTransformer.swift; sourceTree = "<group>"; tabWidth = 4; };
AF4AFD991DAA3462002B6DC9 /* YINUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = YINUtil.swift; sourceTree = "<group>"; tabWidth = 4; };
AFFF3FF01DB633B4004AD9D9 /* YINEstimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YINEstimator.swift; sourceTree = "<group>"; };
D51575AB1C343B77006F8E75 /* Beethoven.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Beethoven.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D51575B51C343B77006F8E75 /* Beethoven-iOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Beethoven-iOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D59CB1371C345E0A00290B63 /* Config.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
D59CB1391C345E0A00290B63 /* Buffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Buffer.swift; sourceTree = "<group>"; };
D59CB13B1C345E0A00290B63 /* EstimationError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EstimationError.swift; sourceTree = "<group>"; };
D59CB13C1C345E0A00290B63 /* EstimationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EstimationFactory.swift; sourceTree = "<group>"; };
D59CB13C1C345E0A00290B63 /* EstimationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = EstimationFactory.swift; sourceTree = "<group>"; tabWidth = 2; };
D59CB13D1C345E0A00290B63 /* EstimationStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EstimationStrategy.swift; sourceTree = "<group>"; };
D59CB13E1C345E0A00290B63 /* Estimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Estimator.swift; sourceTree = "<group>"; };
D59CB13F1C345E0A00290B63 /* LocationEstimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationEstimator.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -130,7 +136,9 @@
D5A49CCE1C343FD700427BF8 /* BeethovenTests */,
D51575AC1C343B77006F8E75 /* Products */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
};
D51575AC1C343B77006F8E75 /* Products */ = {
isa = PBXGroup;
Expand Down Expand Up @@ -172,6 +180,7 @@
D59CB13D1C345E0A00290B63 /* EstimationStrategy.swift */,
D59CB13E1C345E0A00290B63 /* Estimator.swift */,
D59CB13F1C345E0A00290B63 /* LocationEstimator.swift */,
AF4AFD991DAA3462002B6DC9 /* YINUtil.swift */,
);
path = Estimation;
sourceTree = "<group>";
Expand All @@ -186,6 +195,7 @@
D59CB1451C345E0A00290B63 /* QuadradicEstimator.swift */,
D59CB1461C345E0A00290B63 /* QuinnsFirstEstimator.swift */,
D59CB1471C345E0A00290B63 /* QuinnsSecondEstimator.swift */,
AFFF3FF01DB633B4004AD9D9 /* YINEstimator.swift */,
);
path = Strategies;
sourceTree = "<group>";
Expand Down Expand Up @@ -232,6 +242,7 @@
children = (
D59CB1521C345E0A00290B63 /* FFTTransformer.swift */,
D59CB1531C345E0A00290B63 /* SimpleTransformer.swift */,
AF3190511DABE01600C897CA /* YINTransformer.swift */,
);
path = Strategies;
sourceTree = "<group>";
Expand Down Expand Up @@ -495,9 +506,11 @@
D59CB16D1C345E0A00290B63 /* TransformFactory.swift in Sources */,
D59CB1631C345E0A00290B63 /* QuinnsFirstEstimator.swift in Sources */,
D59CB15B1C345E0A00290B63 /* EstimationStrategy.swift in Sources */,
AF4AFD9A1DAA3462002B6DC9 /* YINUtil.swift in Sources */,
D59CB15E1C345E0A00290B63 /* BarycentricEstimator.swift in Sources */,
D59CB1621C345E0A00290B63 /* QuadradicEstimator.swift in Sources */,
D59CB1591C345E0A00290B63 /* EstimationError.swift in Sources */,
AFFF3FF11DB633B4004AD9D9 /* YINEstimator.swift in Sources */,
D59CB1671C345E0A00290B63 /* SignalTracker.swift in Sources */,
D59CB16C1C345E0A00290B63 /* Transformer.swift in Sources */,
D59CB1661C345E0A00290B63 /* PitchEngine.swift in Sources */,
Expand All @@ -508,6 +521,7 @@
D59CB1571C345E0A00290B63 /* Config.swift in Sources */,
D59CB1681C345E0A00290B63 /* InputSignalTracker.swift in Sources */,
D59CB1581C345E0A00290B63 /* Buffer.swift in Sources */,
AF3190521DABE01600C897CA /* YINTransformer.swift in Sources */,
D59CB16A1C345E0A00290B63 /* FFTTransformer.swift in Sources */,
D59CB15A1C345E0A00290B63 /* EstimationFactory.swift in Sources */,
);
Expand Down
25 changes: 21 additions & 4 deletions Example/GuitarTuner/GuitarTuner.xcodeproj/project.pbxproj
Expand Up @@ -101,7 +101,9 @@
7FCBD55DDFAE042D34748647 /* Frameworks */,
28B4E9F09A7A47F3AF3538A7 /* Pods */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
};
D57D40FE1BE95A350026B005 /* Products */ = {
isa = PBXGroup;
Expand All @@ -118,7 +120,7 @@
isa = PBXNativeTarget;
buildConfigurationList = D57D410F1BE95A350026B005 /* Build configuration list for PBXNativeTarget "GuitarTuner" */;
buildPhases = (
0E47FCD898C9F86D6AB5429F /* 📦 Check Pods Manifest.lock */,
0E47FCD898C9F86D6AB5429F /* [CP] Check Pods Manifest.lock */,
1962EBAD1F8E34314E982594 /* [CP] Check Pods Manifest.lock */,
D57D40F91BE95A350026B005 /* Sources */,
D57D40FA1BE95A350026B005 /* Frameworks */,
Expand All @@ -143,11 +145,13 @@
D57D40F51BE95A350026B005 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "Vadym Markov";
TargetAttributes = {
D57D40FC1BE95A350026B005 = {
CreatedOnToolsVersion = 7.0.1;
DevelopmentTeam = 6YMA3EN78R;
LastSwiftMigration = 0800;
};
};
};
Expand Down Expand Up @@ -182,14 +186,14 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
0E47FCD898C9F86D6AB5429F /* 📦 Check Pods Manifest.lock */ = {
0E47FCD898C9F86D6AB5429F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "📦 Check Pods Manifest.lock";
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -311,8 +315,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
Expand All @@ -339,6 +345,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
Expand All @@ -355,8 +362,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
Expand All @@ -375,6 +384,8 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
Expand All @@ -383,23 +394,29 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 1B8EABAEB6DB7CDA44CCC1AD /* Pods-GuitarTuner.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 6YMA3EN78R;
INFOPLIST_FILE = "$(SRCROOT)/GuitarTuner/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.vadymmarkov.GuitarTuner;
PRODUCT_NAME = GuitarTuner;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
D57D41111BE95A350026B005 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 00C49D4F07D54BCD11781B94 /* Pods-GuitarTuner.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 6YMA3EN78R;
INFOPLIST_FILE = "$(SRCROOT)/GuitarTuner/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.vadymmarkov.GuitarTuner;
PRODUCT_NAME = GuitarTuner;
SWIFT_VERSION = 3.0;
};
name = Release;
};
Expand Down
2 changes: 2 additions & 0 deletions Example/GuitarTuner/GuitarTuner/Info.plist
Expand Up @@ -22,6 +22,8 @@
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMicrophoneUsageDescription</key>
<string>app needs microphone access</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
12 changes: 6 additions & 6 deletions Example/GuitarTuner/GuitarTuner/Source/AppDelegate.swift
Expand Up @@ -16,8 +16,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return controller
}()

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = navigationController

applyStyles()
Expand All @@ -29,12 +29,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func applyStyles() {
let navigationBar = UINavigationBar.appearance()
navigationBar.barStyle = .Black
navigationBar.barTintColor = UIColor.hex("111011")
navigationBar.translucent = false
navigationBar.barStyle = .black
navigationBar.barTintColor = UIColor(hex: "111011")
navigationBar.isTranslucent = false
navigationBar.shadowImage = UIImage()
navigationBar.titleTextAttributes = [
NSForegroundColorAttributeName: UIColor.whiteColor()
NSForegroundColorAttributeName: UIColor.white
]
}
}
68 changes: 38 additions & 30 deletions Example/GuitarTuner/GuitarTuner/Source/ViewController.swift
Expand Up @@ -9,9 +9,9 @@ class ViewController: UIViewController {
lazy var noteLabel: UILabel = {
let label = UILabel()
label.text = "--"
label.font = UIFont.boldSystemFontOfSize(65)
label.textColor = UIColor.hex("DCD9DB")
label.textAlignment = .Center
label.font = UIFont.boldSystemFont(ofSize: 65)
label.textColor = UIColor(hex: "DCD9DB")
label.textAlignment = .center
label.numberOfLines = 0
label.sizeToFit()

Expand All @@ -20,31 +20,34 @@ class ViewController: UIViewController {

lazy var offsetLabel: UILabel = { [unowned self] in
let label = UILabel()
label.font = UIFont.systemFontOfSize(28)
label.textColor = UIColor.whiteColor()
label.textAlignment = .Center
label.font = UIFont.systemFont(ofSize: 28)
label.textColor = UIColor.white
label.textAlignment = .center
label.numberOfLines = 0
label.sizeToFit()

return label
}()

lazy var actionButton: UIButton = { [unowned self] in
let button = UIButton(type: .System)
let button = UIButton(type: .system)
button.layer.cornerRadius = 20
button.backgroundColor = UIColor.hex("3DAFAE")
button.titleLabel?.font = UIFont.systemFontOfSize(20)
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button.backgroundColor = UIColor(hex: "3DAFAE")
button.titleLabel?.font = UIFont.systemFont(ofSize: 20)
button.setTitleColor(UIColor.white, for: UIControlState())

button.addTarget(self, action: #selector(ViewController.actionButtonDidPress(_:)),
forControlEvents: .TouchUpInside)
button.setTitle("Start".uppercaseString, forState: .Normal)
for: .touchUpInside)
button.setTitle("Start".uppercased(), for: UIControlState())

return button
}()

lazy var pitchEngine: PitchEngine = { [unowned self] in
let pitchEngine = PitchEngine(delegate: self)
var config = Config()
config.transformStrategy = .yin
config.estimationStrategy = .yin
let pitchEngine = PitchEngine(config: config, delegate: self)
pitchEngine.levelThreshold = -30.0

return pitchEngine
Expand All @@ -55,8 +58,8 @@ class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()

title = "Tuner".uppercaseString
view.backgroundColor = UIColor.hex("111011")
title = "Tuner".uppercased()
view.backgroundColor = UIColor(hex: "111011")

[noteLabel, actionButton, offsetLabel].forEach {
view.addSubview($0)
Expand All @@ -67,25 +70,25 @@ class ViewController: UIViewController {

// MARK: - Action methods

func actionButtonDidPress(button: UIButton) {
func actionButtonDidPress(_ button: UIButton) {
let text = pitchEngine.active
? NSLocalizedString("Start", comment: "").uppercaseString
: NSLocalizedString("Stop", comment: "").uppercaseString
? NSLocalizedString("Start", comment: "").uppercased()
: NSLocalizedString("Stop", comment: "").uppercased()

button.setTitle(text, forState: .Normal)
button.setTitle(text, for: .normal)
button.backgroundColor = pitchEngine.active
? UIColor.hex("3DAFAE")
: UIColor.hex("E13C6C")
? UIColor(hex: "3DAFAE")
: UIColor(hex: "E13C6C")

noteLabel.text = "--"
pitchEngine.active ? pitchEngine.stop() : pitchEngine.start()
offsetLabel.hidden = !pitchEngine.active
offsetLabel.isHidden = !pitchEngine.active
}

// MARK: - Constrains

func setupLayout() {
let totalSize = UIScreen.mainScreen().bounds
let totalSize = UIScreen.main.bounds

constrain(actionButton, noteLabel, offsetLabel) {
actionButton, noteLabel, offsetLabel in
Expand All @@ -111,16 +114,16 @@ class ViewController: UIViewController {

// MARK: - UI

func offsetColor(offsetPercentage: Double) -> UIColor {
func offsetColor(_ offsetPercentage: Double) -> UIColor {
let color: UIColor

switch abs(offsetPercentage) {
case 0...5:
color = UIColor.hex("3DAFAE")
color = UIColor(hex: "3DAFAE")
case 6...25:
color = UIColor.hex("FDFFB1")
color = UIColor(hex: "FDFFB1")
default:
color = UIColor.hex("E13C6C")
color = UIColor(hex: "E13C6C")
}

return color
Expand All @@ -131,7 +134,7 @@ class ViewController: UIViewController {

extension ViewController: PitchEngineDelegate {

func pitchEngineDidRecievePitch(pitchEngine: PitchEngine, pitch: Pitch) {
func pitchEngineDidReceivePitch(_ pitchEngine: PitchEngine, pitch: Pitch) {
noteLabel.text = pitch.note.string

let offsetPercentage = pitch.closestOffset.percentage
Expand All @@ -148,10 +151,15 @@ extension ViewController: PitchEngineDelegate {

offsetLabel.text = "\(prefix)" + String(format:"%.2f", absOffsetPercentage) + "%"
offsetLabel.textColor = color
offsetLabel.hidden = false
offsetLabel.isHidden = false
}

func pitchEngineDidRecieveError(pitchEngine: PitchEngine, error: ErrorType) {
func pitchEngineDidReceiveError(_ pitchEngine: PitchEngine, error: Error) {
print(error)
}

public func pitchEngineWentBelowLevelThreshold(_ pitchEngine: PitchEngine) {

}

}

0 comments on commit 0192a7d

Please sign in to comment.